/*!
 * Vue.js v1.0.24
 * (c) 2016 Evan You
 * Released under the MIT License.
 */
(function(global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
		typeof define === 'function' && define.amd ? define(factory) :
		(global.Vue = factory());
}(this, function() {
	'use strict';

	function set(obj, key, val) {
		if(hasOwn(obj, key)) {
			obj[key] = val;
			return;
		}
		if(obj._isVue) {
			set(obj._data, key, val);
			return;
		}
		var ob = obj.__ob__;
		if(!ob) {
			obj[key] = val;
			return;
		}
		ob.convert(key, val);
		ob.dep.notify();
		if(ob.vms) {
			var i = ob.vms.length;
			while(i--) {
				var vm = ob.vms[i];
				vm._proxy(key);
				vm._digest();
			}
		}
		return val;
	}

	/**
	 * Delete a property and trigger change if necessary.
	 *
	 * @param {Object} obj
	 * @param {String} key
	 */

	function del(obj, key) {
		if(!hasOwn(obj, key)) {
			return;
		}
		delete obj[key];
		var ob = obj.__ob__;
		if(!ob) {
			if(obj._isVue) {
				delete obj._data[key];
				obj._digest();
			}
			return;
		}
		ob.dep.notify();
		if(ob.vms) {
			var i = ob.vms.length;
			while(i--) {
				var vm = ob.vms[i];
				vm._unproxy(key);
				vm._digest();
			}
		}
	}

	var hasOwnProperty = Object.prototype.hasOwnProperty;
	/**
	 * Check whether the object has the property.
	 *
	 * @param {Object} obj
	 * @param {String} key
	 * @return {Boolean}
	 */

	function hasOwn(obj, key) {
		return hasOwnProperty.call(obj, key);
	}

	/**
	 * Check if an expression is a literal value.
	 *
	 * @param {String} exp
	 * @return {Boolean}
	 */

	var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/;

	function isLiteral(exp) {
		return literalValueRE.test(exp);
	}

	/**
	 * Check if a string starts with $ or _
	 *
	 * @param {String} str
	 * @return {Boolean}
	 */

	function isReserved(str) {
		var c = (str + '').charCodeAt(0);
		return c === 0x24 || c === 0x5F;
	}

	/**
	 * Guard text output, make sure undefined outputs
	 * empty string
	 *
	 * @param {*} value
	 * @return {String}
	 */

	function _toString(value) {
		return value == null ? '' : value.toString();
	}

	/**
	 * Check and convert possible numeric strings to numbers
	 * before setting back to data
	 *
	 * @param {*} value
	 * @return {*|Number}
	 */

	function toNumber(value) {
		if(typeof value !== 'string') {
			return value;
		} else {
			var parsed = Number(value);
			return isNaN(parsed) ? value : parsed;
		}
	}

	/**
	 * Convert string boolean literals into real booleans.
	 *
	 * @param {*} value
	 * @return {*|Boolean}
	 */

	function toBoolean(value) {
		return value === 'true' ? true : value === 'false' ? false : value;
	}

	/**
	 * Strip quotes from a string
	 *
	 * @param {String} str
	 * @return {String | false}
	 */

	function stripQuotes(str) {
		var a = str.charCodeAt(0);
		var b = str.charCodeAt(str.length - 1);
		return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
	}

	/**
	 * Camelize a hyphen-delmited string.
	 *
	 * @param {String} str
	 * @return {String}
	 */

	var camelizeRE = /-(\w)/g;

	function camelize(str) {
		return str.replace(camelizeRE, toUpper);
	}

	function toUpper(_, c) {
		return c ? c.toUpperCase() : '';
	}

	/**
	 * Hyphenate a camelCase string.
	 *
	 * @param {String} str
	 * @return {String}
	 */

	var hyphenateRE = /([a-z\d])([A-Z])/g;

	function hyphenate(str) {
		return str.replace(hyphenateRE, '$1-$2').toLowerCase();
	}

	/**
	 * Converts hyphen/underscore/slash delimitered names into
	 * camelized classNames.
	 *
	 * e.g. my-component => MyComponent
	 *      some_else    => SomeElse
	 *      some/comp    => SomeComp
	 *
	 * @param {String} str
	 * @return {String}
	 */

	var classifyRE = /(?:^|[-_\/])(\w)/g;

	function classify(str) {
		return str.replace(classifyRE, toUpper);
	}

	/**
	 * Simple bind, faster than native
	 *
	 * @param {Function} fn
	 * @param {Object} ctx
	 * @return {Function}
	 */

	function bind(fn, ctx) {
		return function(a) {
			var l = arguments.length;
			return l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx);
		};
	}

	/**
	 * Convert an Array-like object to a real Array.
	 *
	 * @param {Array-like} list
	 * @param {Number} [start] - start index
	 * @return {Array}
	 */

	function toArray(list, start) {
		start = start || 0;
		var i = list.length - start;
		var ret = new Array(i);
		while(i--) {
			ret[i] = list[i + start];
		}
		return ret;
	}

	/**
	 * Mix properties into target object.
	 *
	 * @param {Object} to
	 * @param {Object} from
	 */

	function extend(to, from) {
		var keys = Object.keys(from);
		var i = keys.length;
		while(i--) {
			to[keys[i]] = from[keys[i]];
		}
		return to;
	}

	/**
	 * Quick object check - this is primarily used to tell
	 * Objects from primitive values when we know the value
	 * is a JSON-compliant type.
	 *
	 * @param {*} obj
	 * @return {Boolean}
	 */

	function isObject(obj) {
		return obj !== null && typeof obj === 'object';
	}

	/**
	 * Strict object type check. Only returns true
	 * for plain JavaScript objects.
	 *
	 * @param {*} obj
	 * @return {Boolean}
	 */

	var toString = Object.prototype.toString;
	var OBJECT_STRING = '[object Object]';

	function isPlainObject(obj) {
		return toString.call(obj) === OBJECT_STRING;
	}

	/**
	 * Array type check.
	 *
	 * @param {*} obj
	 * @return {Boolean}
	 */

	var isArray = Array.isArray;

	/**
	 * Define a property.
	 *
	 * @param {Object} obj
	 * @param {String} key
	 * @param {*} val
	 * @param {Boolean} [enumerable]
	 */

	function def(obj, key, val, enumerable) {
		Object.defineProperty(obj, key, {
			value: val,
			enumerable: !!enumerable,
			writable: true,
			configurable: true
		});
	}

	/**
	 * Debounce a function so it only gets called after the
	 * input stops arriving after the given wait period.
	 *
	 * @param {Function} func
	 * @param {Number} wait
	 * @return {Function} - the debounced function
	 */

	function _debounce(func, wait) {
		var timeout, args, context, timestamp, result;
		var later = function later() {
			var last = Date.now() - timestamp;
			if(last < wait && last >= 0) {
				timeout = setTimeout(later, wait - last);
			} else {
				timeout = null;
				result = func.apply(context, args);
				if(!timeout) context = args = null;
			}
		};
		return function() {
			context = this;
			args = arguments;
			timestamp = Date.now();
			if(!timeout) {
				timeout = setTimeout(later, wait);
			}
			return result;
		};
	}

	/**
	 * Manual indexOf because it's slightly faster than
	 * native.
	 *
	 * @param {Array} arr
	 * @param {*} obj
	 */

	function indexOf(arr, obj) {
		var i = arr.length;
		while(i--) {
			if(arr[i] === obj) return i;
		}
		return -1;
	}

	/**
	 * Make a cancellable version of an async callback.
	 *
	 * @param {Function} fn
	 * @return {Function}
	 */

	function cancellable(fn) {
		var cb = function cb() {
			if(!cb.cancelled) {
				return fn.apply(this, arguments);
			}
		};
		cb.cancel = function() {
			cb.cancelled = true;
		};
		return cb;
	}

	/**
	 * Check if two values are loosely equal - that is,
	 * if they are plain objects, do they have the same shape?
	 *
	 * @param {*} a
	 * @param {*} b
	 * @return {Boolean}
	 */

	function looseEqual(a, b) {
		/* eslint-disable eqeqeq */
		return a == b || (isObject(a) && isObject(b) ? JSON.stringify(a) === JSON.stringify(b) : false);
		/* eslint-enable eqeqeq */
	}

	var hasProto = ('__proto__' in {});

	// Browser environment sniffing
	var inBrowser = typeof window !== 'undefined' && Object.prototype.toString.call(window) !== '[object Object]';

	// detect devtools
	var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;

	// UA sniffing for working around browser-specific quirks
	var UA = inBrowser && window.navigator.userAgent.toLowerCase();
	var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
	var isAndroid = UA && UA.indexOf('android') > 0;
	var isIos = UA && /(iphone|ipad|ipod|ios)/i.test(UA);
	var isWechat = UA && UA.indexOf('micromessenger') > 0;

	var transitionProp = undefined;
	var transitionEndEvent = undefined;
	var animationProp = undefined;
	var animationEndEvent = undefined;

	// Transition property/event sniffing
	if(inBrowser && !isIE9) {
		var isWebkitTrans = window.ontransitionend === undefined && window.onwebkittransitionend !== undefined;
		var isWebkitAnim = window.onanimationend === undefined && window.onwebkitanimationend !== undefined;
		transitionProp = isWebkitTrans ? 'WebkitTransition' : 'transition';
		transitionEndEvent = isWebkitTrans ? 'webkitTransitionEnd' : 'transitionend';
		animationProp = isWebkitAnim ? 'WebkitAnimation' : 'animation';
		animationEndEvent = isWebkitAnim ? 'webkitAnimationEnd' : 'animationend';
	}

	/**
	 * Defer a task to execute it asynchronously. Ideally this
	 * should be executed as a microtask, so we leverage
	 * MutationObserver if it's available, and fallback to
	 * setTimeout(0).
	 *
	 * @param {Function} cb
	 * @param {Object} ctx
	 */

	var nextTick = (function() {
		var callbacks = [];
		var pending = false;
		var timerFunc;

		function nextTickHandler() {
			pending = false;
			var copies = callbacks.slice(0);
			callbacks = [];
			for(var i = 0; i < copies.length; i++) {
				copies[i]();
			}
		}

		/* istanbul ignore if */
		if(typeof MutationObserver !== 'undefined' && !(isWechat && isIos)) {
			var counter = 1;
			var observer = new MutationObserver(nextTickHandler);
			var textNode = document.createTextNode(counter);
			observer.observe(textNode, {
				characterData: true
			});
			timerFunc = function() {
				counter = (counter + 1) % 2;
				textNode.data = counter;
			};
		} else {
			// webpack attempts to inject a shim for setImmediate
			// if it is used as a global, so we have to work around that to
			// avoid bundling unnecessary code.
			var context = inBrowser ? window : typeof global !== 'undefined' ? global : {};
			timerFunc = context.setImmediate || setTimeout;
		}
		return function(cb, ctx) {
			var func = ctx ? function() {
				cb.call(ctx);
			} : cb;
			callbacks.push(func);
			if(pending) return;
			pending = true;
			timerFunc(nextTickHandler, 0);
		};
	})();

	var _Set = undefined;
	/* istanbul ignore if */
	if(typeof Set !== 'undefined' && Set.toString().match(/native code/)) {
		// use native Set when available.
		_Set = Set;
	} else {
		// a non-standard Set polyfill that only works with primitive keys.
		_Set = function() {
			this.set = Object.create(null);
		};
		_Set.prototype.has = function(key) {
			return this.set[key] !== undefined;
		};
		_Set.prototype.add = function(key) {
			this.set[key] = 1;
		};
		_Set.prototype.clear = function() {
			this.set = Object.create(null);
		};
	}

	function Cache(limit) {
		this.size = 0;
		this.limit = limit;
		this.head = this.tail = undefined;
		this._keymap = Object.create(null);
	}

	var p = Cache.prototype;

	/**
	 * Put <value> into the cache associated with <key>.
	 * Returns the entry which was removed to make room for
	 * the new entry. Otherwise undefined is returned.
	 * (i.e. if there was enough room already).
	 *
	 * @param {String} key
	 * @param {*} value
	 * @return {Entry|undefined}
	 */

	p.put = function(key, value) {
		var removed;
		if(this.size === this.limit) {
			removed = this.shift();
		}

		var entry = this.get(key, true);
		if(!entry) {
			entry = {
				key: key
			};
			this._keymap[key] = entry;
			if(this.tail) {
				this.tail.newer = entry;
				entry.older = this.tail;
			} else {
				this.head = entry;
			}
			this.tail = entry;
			this.size++;
		}
		entry.value = value;

		return removed;
	};

	/**
	 * Purge the least recently used (oldest) entry from the
	 * cache. Returns the removed entry or undefined if the
	 * cache was empty.
	 */

	p.shift = function() {
		var entry = this.head;
		if(entry) {
			this.head = this.head.newer;
			this.head.older = undefined;
			entry.newer = entry.older = undefined;
			this._keymap[entry.key] = undefined;
			this.size--;
		}
		return entry;
	};

	/**
	 * Get and register recent use of <key>. Returns the value
	 * associated with <key> or undefined if not in cache.
	 *
	 * @param {String} key
	 * @param {Boolean} returnEntry
	 * @return {Entry|*}
	 */

	p.get = function(key, returnEntry) {
		var entry = this._keymap[key];
		if(entry === undefined) return;
		if(entry === this.tail) {
			return returnEntry ? entry : entry.value;
		}
		// HEAD--------------TAIL
		//   <.older   .newer>
		//  <--- add direction --
		//   A  B  C  <D>  E
		if(entry.newer) {
			if(entry === this.head) {
				this.head = entry.newer;
			}
			entry.newer.older = entry.older; // C <-- E.
		}
		if(entry.older) {
			entry.older.newer = entry.newer; // C. --> E
		}
		entry.newer = undefined; // D --x
		entry.older = this.tail; // D. --> E
		if(this.tail) {
			this.tail.newer = entry; // E. <-- D
		}
		this.tail = entry;
		return returnEntry ? entry : entry.value;
	};

	var cache$1 = new Cache(1000);
	var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g;
	var reservedArgRE = /^in$|^-?\d+/;

	/**
	 * Parser state
	 */

	var str;
	var dir;
	var c;
	var prev;
	var i;
	var l;
	var lastFilterIndex;
	var inSingle;
	var inDouble;
	var curly;
	var square;
	var paren;
	/**
	 * Push a filter to the current directive object
	 */

	function pushFilter() {
		var exp = str.slice(lastFilterIndex, i).trim();
		var filter;
		if(exp) {
			filter = {};
			var tokens = exp.match(filterTokenRE);
			filter.name = tokens[0];
			if(tokens.length > 1) {
				filter.args = tokens.slice(1).map(processFilterArg);
			}
		}
		if(filter) {
			(dir.filters = dir.filters || []).push(filter);
		}
		lastFilterIndex = i + 1;
	}

	/**
	 * Check if an argument is dynamic and strip quotes.
	 *
	 * @param {String} arg
	 * @return {Object}
	 */

	function processFilterArg(arg) {
		if(reservedArgRE.test(arg)) {
			return {
				value: toNumber(arg),
				dynamic: false
			};
		} else {
			var stripped = stripQuotes(arg);
			var dynamic = stripped === arg;
			return {
				value: dynamic ? arg : stripped,
				dynamic: dynamic
			};
		}
	}

	/**
	 * Parse a directive value and extract the expression
	 * and its filters into a descriptor.
	 *
	 * Example:
	 *
	 * "a + 1 | uppercase" will yield:
	 * {
	 *   expression: 'a + 1',
	 *   filters: [
	 *     { name: 'uppercase', args: null }
	 *   ]
	 * }
	 *
	 * @param {String} s
	 * @return {Object}
	 */

	function parseDirective(s) {
		var hit = cache$1.get(s);
		if(hit) {
			return hit;
		}

		// reset parser state
		str = s;
		inSingle = inDouble = false;
		curly = square = paren = 0;
		lastFilterIndex = 0;
		dir = {};

		for(i = 0, l = str.length; i < l; i++) {
			prev = c;
			c = str.charCodeAt(i);
			if(inSingle) {
				// check single quote
				if(c === 0x27 && prev !== 0x5C) inSingle = !inSingle;
			} else if(inDouble) {
				// check double quote
				if(c === 0x22 && prev !== 0x5C) inDouble = !inDouble;
			} else if(c === 0x7C && // pipe
				str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) {
				if(dir.expression == null) {
					// first filter, end of expression
					lastFilterIndex = i + 1;
					dir.expression = str.slice(0, i).trim();
				} else {
					// already has filter
					pushFilter();
				}
			} else {
				switch(c) {
					case 0x22:
						inDouble = true;
						break; // "
					case 0x27:
						inSingle = true;
						break; // '
					case 0x28:
						paren++;
						break; // (
					case 0x29:
						paren--;
						break; // )
					case 0x5B:
						square++;
						break; // [
					case 0x5D:
						square--;
						break; // ]
					case 0x7B:
						curly++;
						break; // {
					case 0x7D:
						curly--;
						break; // }
				}
			}
		}

		if(dir.expression == null) {
			dir.expression = str.slice(0, i).trim();
		} else if(lastFilterIndex !== 0) {
			pushFilter();
		}

		cache$1.put(s, dir);
		return dir;
	}

	var directive = Object.freeze({
		parseDirective: parseDirective
	});

	var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g;
	var cache = undefined;
	var tagRE = undefined;
	var htmlRE = undefined;
	/**
	 * Escape a string so it can be used in a RegExp
	 * constructor.
	 *
	 * @param {String} str
	 */

	function escapeRegex(str) {
		return str.replace(regexEscapeRE, '\\$&');
	}

	function compileRegex() {
		var open = escapeRegex(config.delimiters[0]);
		var close = escapeRegex(config.delimiters[1]);
		var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]);
		var unsafeClose = escapeRegex(config.unsafeDelimiters[1]);
		tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g');
		htmlRE = new RegExp('^' + unsafeOpen + '.*' + unsafeClose + '$');
		// reset cache
		cache = new Cache(1000);
	}

	/**
	 * Parse a template text string into an array of tokens.
	 *
	 * @param {String} text
	 * @return {Array<Object> | null}
	 *               - {String} type
	 *               - {String} value
	 *               - {Boolean} [html]
	 *               - {Boolean} [oneTime]
	 */

	function parseText(text) {
		if(!cache) {
			compileRegex();
		}
		var hit = cache.get(text);
		if(hit) {
			return hit;
		}
		if(!tagRE.test(text)) {
			return null;
		}
		var tokens = [];
		var lastIndex = tagRE.lastIndex = 0;
		var match, index, html, value, first, oneTime;
		/* eslint-disable no-cond-assign */
		while(match = tagRE.exec(text)) {
			/* eslint-enable no-cond-assign */
			index = match.index;
			// push text token
			if(index > lastIndex) {
				tokens.push({
					value: text.slice(lastIndex, index)
				});
			}
			// tag token
			html = htmlRE.test(match[0]);
			value = html ? match[1] : match[2];
			first = value.charCodeAt(0);
			oneTime = first === 42; // *
			value = oneTime ? value.slice(1) : value;
			tokens.push({
				tag: true,
				value: value.trim(),
				html: html,
				oneTime: oneTime
			});
			lastIndex = index + match[0].length;
		}
		if(lastIndex < text.length) {
			tokens.push({
				value: text.slice(lastIndex)
			});
		}
		cache.put(text, tokens);
		return tokens;
	}

	/**
	 * Format a list of tokens into an expression.
	 * e.g. tokens parsed from 'a {{b}} c' can be serialized
	 * into one single expression as '"a " + b + " c"'.
	 *
	 * @param {Array} tokens
	 * @param {Vue} [vm]
	 * @return {String}
	 */

	function tokensToExp(tokens, vm) {
		if(tokens.length > 1) {
			return tokens.map(function(token) {
				return formatToken(token, vm);
			}).join('+');
		} else {
			return formatToken(tokens[0], vm, true);
		}
	}

	/**
	 * Format a single token.
	 *
	 * @param {Object} token
	 * @param {Vue} [vm]
	 * @param {Boolean} [single]
	 * @return {String}
	 */

	function formatToken(token, vm, single) {
		return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"';
	}

	/**
	 * For an attribute with multiple interpolation tags,
	 * e.g. attr="some-{{thing | filter}}", in order to combine
	 * the whole thing into a single watchable expression, we
	 * have to inline those filters. This function does exactly
	 * that. This is a bit hacky but it avoids heavy changes
	 * to directive parser and watcher mechanism.
	 *
	 * @param {String} exp
	 * @param {Boolean} single
	 * @return {String}
	 */

	var filterRE = /[^|]\|[^|]/;

	function inlineFilters(exp, single) {
		if(!filterRE.test(exp)) {
			return single ? exp : '(' + exp + ')';
		} else {
			var dir = parseDirective(exp);
			if(!dir.filters) {
				return '(' + exp + ')';
			} else {
				return 'this._applyFilters(' + dir.expression + // value
					',null,' + // oldValue (null for read)
					JSON.stringify(dir.filters) + // filter descriptors
					',false)'; // write?
			}
		}
	}

	var text = Object.freeze({
		compileRegex: compileRegex,
		parseText: parseText,
		tokensToExp: tokensToExp
	});

	var delimiters = ['{{', '}}'];
	var unsafeDelimiters = ['{{{', '}}}'];

	var config = Object.defineProperties({

		/**
		 * Whether to print debug messages.
		 * Also enables stack trace for warnings.
		 *
		 * @type {Boolean}
		 */

		debug: false,

		/**
		 * Whether to suppress warnings.
		 *
		 * @type {Boolean}
		 */

		silent: false,

		/**
		 * Whether to use async rendering.
		 */

		async: true,

		/**
		 * Whether to warn against errors caught when evaluating
		 * expressions.
		 */

		warnExpressionErrors: true,

		/**
		 * Whether to allow devtools inspection.
		 * Disabled by default in production builds.
		 */

		devtools: 'development' !== 'production',

		/**
		 * Internal flag to indicate the delimiters have been
		 * changed.
		 *
		 * @type {Boolean}
		 */

		_delimitersChanged: true,

		/**
		 * List of asset types that a component can own.
		 *
		 * @type {Array}
		 */

		_assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'],

		/**
		 * prop binding modes
		 */

		_propBindingModes: {
			ONE_WAY: 0,
			TWO_WAY: 1,
			ONE_TIME: 2
		},

		/**
		 * Max circular updates allowed in a batcher flush cycle.
		 */

		_maxUpdateCount: 100

	}, {
		delimiters: {
			/**
			 * Interpolation delimiters. Changing these would trigger
			 * the text parser to re-compile the regular expressions.
			 *
			 * @type {Array<String>}
			 */

			get: function get() {
				return delimiters;
			},
			set: function set(val) {
				delimiters = val;
				compileRegex();
			},
			configurable: true,
			enumerable: true
		},
		unsafeDelimiters: {
			get: function get() {
				return unsafeDelimiters;
			},
			set: function set(val) {
				unsafeDelimiters = val;
				compileRegex();
			},
			configurable: true,
			enumerable: true
		}
	});

	var warn = undefined;
	var formatComponentName = undefined;

	if('development' !== 'production') {
		(function() {
			var hasConsole = typeof console !== 'undefined';

			warn = function(msg, vm) {
				if(hasConsole && !config.silent) {
					console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : ''));
				}
			};

			formatComponentName = function(vm) {
				var name = vm._isVue ? vm.$options.name : vm.name;
				return name ? ' (found in component: <' + hyphenate(name) + '>)' : '';
			};
		})();
	}

	/**
	 * Append with transition.
	 *
	 * @param {Element} el
	 * @param {Element} target
	 * @param {Vue} vm
	 * @param {Function} [cb]
	 */

	function appendWithTransition(el, target, vm, cb) {
		applyTransition(el, 1, function() {
			target.appendChild(el);
		}, vm, cb);
	}

	/**
	 * InsertBefore with transition.
	 *
	 * @param {Element} el
	 * @param {Element} target
	 * @param {Vue} vm
	 * @param {Function} [cb]
	 */

	function beforeWithTransition(el, target, vm, cb) {
		applyTransition(el, 1, function() {
			before(el, target);
		}, vm, cb);
	}

	/**
	 * Remove with transition.
	 *
	 * @param {Element} el
	 * @param {Vue} vm
	 * @param {Function} [cb]
	 */

	function removeWithTransition(el, vm, cb) {
		applyTransition(el, -1, function() {
			remove(el);
		}, vm, cb);
	}

	/**
	 * Apply transitions with an operation callback.
	 *
	 * @param {Element} el
	 * @param {Number} direction
	 *                  1: enter
	 *                 -1: leave
	 * @param {Function} op - the actual DOM operation
	 * @param {Vue} vm
	 * @param {Function} [cb]
	 */

	function applyTransition(el, direction, op, vm, cb) {
		var transition = el.__v_trans;
		if(!transition ||
			// skip if there are no js hooks and CSS transition is
			// not supported
			!transition.hooks && !transitionEndEvent ||
			// skip transitions for initial compile
			!vm._isCompiled ||
			// if the vm is being manipulated by a parent directive
			// during the parent's compilation phase, skip the
			// animation.
			vm.$parent && !vm.$parent._isCompiled) {
			op();
			if(cb) cb();
			return;
		}
		var action = direction > 0 ? 'enter' : 'leave';
		transition[action](op, cb);
	}

	var transition = Object.freeze({
		appendWithTransition: appendWithTransition,
		beforeWithTransition: beforeWithTransition,
		removeWithTransition: removeWithTransition,
		applyTransition: applyTransition
	});

	/**
	 * Query an element selector if it's not an element already.
	 *
	 * @param {String|Element} el
	 * @return {Element}
	 */

	function query(el) {
		if(typeof el === 'string') {
			var selector = el;
			el = document.querySelector(el);
			if(!el) {
				'development' !== 'production' && warn('Cannot find element: ' + selector);
			}
		}
		return el;
	}

	/**
	 * Check if a node is in the document.
	 * Note: document.documentElement.contains should work here
	 * but always returns false for comment nodes in phantomjs,
	 * making unit tests difficult. This is fixed by doing the
	 * contains() check on the node's parentNode instead of
	 * the node itself.
	 *
	 * @param {Node} node
	 * @return {Boolean}
	 */

	function inDoc(node) {
		if(!node) return false;
		var doc = node.ownerDocument.documentElement;
		var parent = node.parentNode;
		return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent));
	}

	/**
	 * Get and remove an attribute from a node.
	 *
	 * @param {Node} node
	 * @param {String} _attr
	 */

	function getAttr(node, _attr) {
		var val = node.getAttribute(_attr);
		if(val !== null) {
			node.removeAttribute(_attr);
		}
		return val;
	}

	/**
	 * Get an attribute with colon or v-bind: prefix.
	 *
	 * @param {Node} node
	 * @param {String} name
	 * @return {String|null}
	 */

	function getBindAttr(node, name) {
		var val = getAttr(node, ':' + name);
		if(val === null) {
			val = getAttr(node, 'v-bind:' + name);
		}
		return val;
	}

	/**
	 * Check the presence of a bind attribute.
	 *
	 * @param {Node} node
	 * @param {String} name
	 * @return {Boolean}
	 */

	function hasBindAttr(node, name) {
		return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name);
	}

	/**
	 * Insert el before target
	 *
	 * @param {Element} el
	 * @param {Element} target
	 */

	function before(el, target) {
		target.parentNode.insertBefore(el, target);
	}

	/**
	 * Insert el after target
	 *
	 * @param {Element} el
	 * @param {Element} target
	 */

	function after(el, target) {
		if(target.nextSibling) {
			before(el, target.nextSibling);
		} else {
			target.parentNode.appendChild(el);
		}
	}

	/**
	 * Remove el from DOM
	 *
	 * @param {Element} el
	 */

	function remove(el) {
		el.parentNode.removeChild(el);
	}

	/**
	 * Prepend el to target
	 *
	 * @param {Element} el
	 * @param {Element} target
	 */

	function prepend(el, target) {
		if(target.firstChild) {
			before(el, target.firstChild);
		} else {
			target.appendChild(el);
		}
	}

	/**
	 * Replace target with el
	 *
	 * @param {Element} target
	 * @param {Element} el
	 */

	function replace(target, el) {
		var parent = target.parentNode;
		if(parent) {
			parent.replaceChild(el, target);
		}
	}

	/**
	 * Add event listener shorthand.
	 *
	 * @param {Element} el
	 * @param {String} event
	 * @param {Function} cb
	 * @param {Boolean} [useCapture]
	 */

	function on(el, event, cb, useCapture) {
		el.addEventListener(event, cb, useCapture);
	}

	/**
	 * Remove event listener shorthand.
	 *
	 * @param {Element} el
	 * @param {String} event
	 * @param {Function} cb
	 */

	function off(el, event, cb) {
		el.removeEventListener(event, cb);
	}

	/**
	 * For IE9 compat: when both class and :class are present
	 * getAttribute('class') returns wrong value...
	 *
	 * @param {Element} el
	 * @return {String}
	 */

	function getClass(el) {
		var classname = el.className;
		if(typeof classname === 'object') {
			classname = classname.baseVal || '';
		}
		return classname;
	}

	/**
	 * In IE9, setAttribute('class') will result in empty class
	 * if the element also has the :class attribute; However in
	 * PhantomJS, setting `className` does not work on SVG elements...
	 * So we have to do a conditional check here.
	 *
	 * @param {Element} el
	 * @param {String} cls
	 */

	function setClass(el, cls) {
		/* istanbul ignore if */
		if(isIE9 && !/svg$/.test(el.namespaceURI)) {
			el.className = cls;
		} else {
			el.setAttribute('class', cls);
		}
	}

	/**
	 * Add class with compatibility for IE & SVG
	 *
	 * @param {Element} el
	 * @param {String} cls
	 */

	function addClass(el, cls) {
		if(el.classList) {
			el.classList.add(cls);
		} else {
			var cur = ' ' + getClass(el) + ' ';
			if(cur.indexOf(' ' + cls + ' ') < 0) {
				setClass(el, (cur + cls).trim());
			}
		}
	}

	/**
	 * Remove class with compatibility for IE & SVG
	 *
	 * @param {Element} el
	 * @param {String} cls
	 */

	function removeClass(el, cls) {
		if(el.classList) {
			el.classList.remove(cls);
		} else {
			var cur = ' ' + getClass(el) + ' ';
			var tar = ' ' + cls + ' ';
			while(cur.indexOf(tar) >= 0) {
				cur = cur.replace(tar, ' ');
			}
			setClass(el, cur.trim());
		}
		if(!el.className) {
			el.removeAttribute('class');
		}
	}

	/**
	 * Extract raw content inside an element into a temporary
	 * container div
	 *
	 * @param {Element} el
	 * @param {Boolean} asFragment
	 * @return {Element|DocumentFragment}
	 */

	function extractContent(el, asFragment) {
		var child;
		var rawContent;
		/* istanbul ignore if */
		if(isTemplate(el) && isFragment(el.content)) {
			el = el.content;
		}
		if(el.hasChildNodes()) {
			trimNode(el);
			rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div');
			/* eslint-disable no-cond-assign */
			while(child = el.firstChild) {
				/* eslint-enable no-cond-assign */
				rawContent.appendChild(child);
			}
		}
		return rawContent;
	}

	/**
	 * Trim possible empty head/tail text and comment
	 * nodes inside a parent.
	 *
	 * @param {Node} node
	 */

	function trimNode(node) {
		var child;
		/* eslint-disable no-sequences */
		while((child = node.firstChild, isTrimmable(child))) {
			node.removeChild(child);
		}
		while((child = node.lastChild, isTrimmable(child))) {
			node.removeChild(child);
		}
		/* eslint-enable no-sequences */
	}

	function isTrimmable(node) {
		return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8);
	}

	/**
	 * Check if an element is a template tag.
	 * Note if the template appears inside an SVG its tagName
	 * will be in lowercase.
	 *
	 * @param {Element} el
	 */

	function isTemplate(el) {
		return el.tagName && el.tagName.toLowerCase() === 'template';
	}

	/**
	 * Create an "anchor" for performing dom insertion/removals.
	 * This is used in a number of scenarios:
	 * - fragment instance
	 * - v-html
	 * - v-if
	 * - v-for
	 * - component
	 *
	 * @param {String} content
	 * @param {Boolean} persist - IE trashes empty textNodes on
	 *                            cloneNode(true), so in certain
	 *                            cases the anchor needs to be
	 *                            non-empty to be persisted in
	 *                            templates.
	 * @return {Comment|Text}
	 */

	function createAnchor(content, persist) {
		var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : '');
		anchor.__v_anchor = true;
		return anchor;
	}

	/**
	 * Find a component ref attribute that starts with $.
	 *
	 * @param {Element} node
	 * @return {String|undefined}
	 */

	var refRE = /^v-ref:/;

	function findRef(node) {
		if(node.hasAttributes()) {
			var attrs = node.attributes;
			for(var i = 0, l = attrs.length; i < l; i++) {
				var name = attrs[i].name;
				if(refRE.test(name)) {
					return camelize(name.replace(refRE, ''));
				}
			}
		}
	}

	/**
	 * Map a function to a range of nodes .
	 *
	 * @param {Node} node
	 * @param {Node} end
	 * @param {Function} op
	 */

	function mapNodeRange(node, end, op) {
		var next;
		while(node !== end) {
			next = node.nextSibling;
			op(node);
			node = next;
		}
		op(end);
	}

	/**
	 * Remove a range of nodes with transition, store
	 * the nodes in a fragment with correct ordering,
	 * and call callback when done.
	 *
	 * @param {Node} start
	 * @param {Node} end
	 * @param {Vue} vm
	 * @param {DocumentFragment} frag
	 * @param {Function} cb
	 */

	function removeNodeRange(start, end, vm, frag, cb) {
		var done = false;
		var removed = 0;
		var nodes = [];
		mapNodeRange(start, end, function(node) {
			if(node === end) done = true;
			nodes.push(node);
			removeWithTransition(node, vm, onRemoved);
		});

		function onRemoved() {
			removed++;
			if(done && removed >= nodes.length) {
				for(var i = 0; i < nodes.length; i++) {
					frag.appendChild(nodes[i]);
				}
				cb && cb();
			}
		}
	}

	/**
	 * Check if a node is a DocumentFragment.
	 *
	 * @param {Node} node
	 * @return {Boolean}
	 */

	function isFragment(node) {
		return node && node.nodeType === 11;
	}

	/**
	 * Get outerHTML of elements, taking care
	 * of SVG elements in IE as well.
	 *
	 * @param {Element} el
	 * @return {String}
	 */

	function getOuterHTML(el) {
		if(el.outerHTML) {
			return el.outerHTML;
		} else {
			var container = document.createElement('div');
			container.appendChild(el.cloneNode(true));
			return container.innerHTML;
		}
	}

	var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i;
	var reservedTagRE = /^(slot|partial|component)$/i;

	var isUnknownElement = undefined;
	if('development' !== 'production') {
		isUnknownElement = function(el, tag) {
			if(tag.indexOf('-') > -1) {
				// http://stackoverflow.com/a/28210364/1070244
				return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement;
			} else {
				return(/HTMLUnknownElement/.test(el.toString()) &&
					// Chrome returns unknown for several HTML5 elements.
					// https://code.google.com/p/chromium/issues/detail?id=540526
					!/^(data|time|rtc|rb)$/.test(tag)
				);
			}
		};
	}

	/**
	 * Check if an element is a component, if yes return its
	 * component id.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Object|undefined}
	 */

	function checkComponentAttr(el, options) {
		var tag = el.tagName.toLowerCase();
		var hasAttrs = el.hasAttributes();
		if(!commonTagRE.test(tag) && !reservedTagRE.test(tag)) {
			if(resolveAsset(options, 'components', tag)) {
				return { id: tag };
			} else {
				var is = hasAttrs && getIsBinding(el, options);
				if(is) {
					return is;
				} else if('development' !== 'production') {
					var expectedTag = options._componentNameMap && options._componentNameMap[tag];
					if(expectedTag) {
						warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.');
					} else if(isUnknownElement(el, tag)) {
						warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.');
					}
				}
			}
		} else if(hasAttrs) {
			return getIsBinding(el, options);
		}
	}

	/**
	 * Get "is" binding from an element.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Object|undefined}
	 */

	function getIsBinding(el, options) {
		// dynamic syntax
		var exp = el.getAttribute('is');
		if(exp != null) {
			if(resolveAsset(options, 'components', exp)) {
				el.removeAttribute('is');
				return { id: exp };
			}
		} else {
			exp = getBindAttr(el, 'is');
			if(exp != null) {
				return { id: exp, dynamic: true };
			}
		}
	}

	/**
	 * Option overwriting strategies are functions that handle
	 * how to merge a parent option value and a child option
	 * value into the final value.
	 *
	 * All strategy functions follow the same signature:
	 *
	 * @param {*} parentVal
	 * @param {*} childVal
	 * @param {Vue} [vm]
	 */

	var strats = config.optionMergeStrategies = Object.create(null);

	/**
	 * Helper that recursively merges two data objects together.
	 */

	function mergeData(to, from) {
		var key, toVal, fromVal;
		for(key in from) {
			toVal = to[key];
			fromVal = from[key];
			if(!hasOwn(to, key)) {
				set(to, key, fromVal);
			} else if(isObject(toVal) && isObject(fromVal)) {
				mergeData(toVal, fromVal);
			}
		}
		return to;
	}

	/**
	 * Data
	 */

	strats.data = function(parentVal, childVal, vm) {
		if(!vm) {
			// in a Vue.extend merge, both should be functions
			if(!childVal) {
				return parentVal;
			}
			if(typeof childVal !== 'function') {
				'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm);
				return parentVal;
			}
			if(!parentVal) {
				return childVal;
			}
			// when parentVal & childVal are both present,
			// we need to return a function that returns the
			// merged result of both functions... no need to
			// check if parentVal is a function here because
			// it has to be a function to pass previous merges.
			return function mergedDataFn() {
				return mergeData(childVal.call(this), parentVal.call(this));
			};
		} else if(parentVal || childVal) {
			return function mergedInstanceDataFn() {
				// instance merge
				var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal;
				var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined;
				if(instanceData) {
					return mergeData(instanceData, defaultData);
				} else {
					return defaultData;
				}
			};
		}
	};

	/**
	 * El
	 */

	strats.el = function(parentVal, childVal, vm) {
		if(!vm && childVal && typeof childVal !== 'function') {
			'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm);
			return;
		}
		var ret = childVal || parentVal;
		// invoke the element factory if this is instance merge
		return vm && typeof ret === 'function' ? ret.call(vm) : ret;
	};

	/**
	 * Hooks and param attributes are merged as arrays.
	 */

	strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function(parentVal, childVal) {
		return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal;
	};

	/**
	 * Assets
	 *
	 * When a vm is present (instance creation), we need to do
	 * a three-way merge between constructor options, instance
	 * options and parent options.
	 */

	function mergeAssets(parentVal, childVal) {
		var res = Object.create(parentVal || null);
		return childVal ? extend(res, guardArrayAssets(childVal)) : res;
	}

	config._assetTypes.forEach(function(type) {
		strats[type + 's'] = mergeAssets;
	});

	/**
	 * Events & Watchers.
	 *
	 * Events & watchers hashes should not overwrite one
	 * another, so we merge them as arrays.
	 */

	strats.watch = strats.events = function(parentVal, childVal) {
		if(!childVal) return parentVal;
		if(!parentVal) return childVal;
		var ret = {};
		extend(ret, parentVal);
		for(var key in childVal) {
			var parent = ret[key];
			var child = childVal[key];
			if(parent && !isArray(parent)) {
				parent = [parent];
			}
			ret[key] = parent ? parent.concat(child) : [child];
		}
		return ret;
	};

	/**
	 * Other object hashes.
	 */

	strats.props = strats.methods = strats.computed = function(parentVal, childVal) {
		if(!childVal) return parentVal;
		if(!parentVal) return childVal;
		var ret = Object.create(null);
		extend(ret, parentVal);
		extend(ret, childVal);
		return ret;
	};

	/**
	 * Default strategy.
	 */

	var defaultStrat = function defaultStrat(parentVal, childVal) {
		return childVal === undefined ? parentVal : childVal;
	};

	/**
	 * Make sure component options get converted to actual
	 * constructors.
	 *
	 * @param {Object} options
	 */

	function guardComponents(options) {
		if(options.components) {
			var components = options.components = guardArrayAssets(options.components);
			var ids = Object.keys(components);
			var def;
			if('development' !== 'production') {
				var map = options._componentNameMap = {};
			}
			for(var i = 0, l = ids.length; i < l; i++) {
				var key = ids[i];
				if(commonTagRE.test(key) || reservedTagRE.test(key)) {
					'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key);
					continue;
				}
				// record a all lowercase <-> kebab-case mapping for
				// possible custom element case error warning
				if('development' !== 'production') {
					map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key);
				}
				def = components[key];
				if(isPlainObject(def)) {
					components[key] = Vue.extend(def);
				}
			}
		}
	}

	/**
	 * Ensure all props option syntax are normalized into the
	 * Object-based format.
	 *
	 * @param {Object} options
	 */

	function guardProps(options) {
		var props = options.props;
		var i, val;
		if(isArray(props)) {
			options.props = {};
			i = props.length;
			while(i--) {
				val = props[i];
				if(typeof val === 'string') {
					options.props[val] = null;
				} else if(val.name) {
					options.props[val.name] = val;
				}
			}
		} else if(isPlainObject(props)) {
			var keys = Object.keys(props);
			i = keys.length;
			while(i--) {
				val = props[keys[i]];
				if(typeof val === 'function') {
					props[keys[i]] = { type: val };
				}
			}
		}
	}

	/**
	 * Guard an Array-format assets option and converted it
	 * into the key-value Object format.
	 *
	 * @param {Object|Array} assets
	 * @return {Object}
	 */

	function guardArrayAssets(assets) {
		if(isArray(assets)) {
			var res = {};
			var i = assets.length;
			var asset;
			while(i--) {
				asset = assets[i];
				var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id;
				if(!id) {
					'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.');
				} else {
					res[id] = asset;
				}
			}
			return res;
		}
		return assets;
	}

	/**
	 * Merge two option objects into a new one.
	 * Core utility used in both instantiation and inheritance.
	 *
	 * @param {Object} parent
	 * @param {Object} child
	 * @param {Vue} [vm] - if vm is present, indicates this is
	 *                     an instantiation merge.
	 */

	function mergeOptions(parent, child, vm) {
		guardComponents(child);
		guardProps(child);
		if('development' !== 'production') {
			if(child.propsData && !vm) {
				warn('propsData can only be used as an instantiation option.');
			}
		}
		var options = {};
		var key;
		if(child['extends']) {
			parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm);
		}
		if(child.mixins) {
			for(var i = 0, l = child.mixins.length; i < l; i++) {
				parent = mergeOptions(parent, child.mixins[i], vm);
			}
		}
		for(key in parent) {
			mergeField(key);
		}
		for(key in child) {
			if(!hasOwn(parent, key)) {
				mergeField(key);
			}
		}

		function mergeField(key) {
			var strat = strats[key] || defaultStrat;
			options[key] = strat(parent[key], child[key], vm, key);
		}
		return options;
	}

	/**
	 * Resolve an asset.
	 * This function is used because child instances need access
	 * to assets defined in its ancestor chain.
	 *
	 * @param {Object} options
	 * @param {String} type
	 * @param {String} id
	 * @param {Boolean} warnMissing
	 * @return {Object|Function}
	 */

	function resolveAsset(options, type, id, warnMissing) {
		/* istanbul ignore if */
		if(typeof id !== 'string') {
			return;
		}
		var assets = options[type];
		var camelizedId;
		var res = assets[id] ||
			// camelCase ID
			assets[camelizedId = camelize(id)] ||
			// Pascal Case ID
			assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)];
		if('development' !== 'production' && warnMissing && !res) {
			warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options);
		}
		return res;
	}

	var uid$1 = 0;

	/**
	 * A dep is an observable that can have multiple
	 * directives subscribing to it.
	 *
	 * @constructor
	 */
	function Dep() {
		this.id = uid$1++;
		this.subs = [];
	}

	// the current target watcher being evaluated.
	// this is globally unique because there could be only one
	// watcher being evaluated at any time.
	Dep.target = null;

	/**
	 * Add a directive subscriber.
	 *
	 * @param {Directive} sub
	 */

	Dep.prototype.addSub = function(sub) {
		this.subs.push(sub);
	};

	/**
	 * Remove a directive subscriber.
	 *
	 * @param {Directive} sub
	 */

	Dep.prototype.removeSub = function(sub) {
		this.subs.$remove(sub);
	};

	/**
	 * Add self as a dependency to the target watcher.
	 */

	Dep.prototype.depend = function() {
		Dep.target.addDep(this);
	};

	/**
	 * Notify all subscribers of a new value.
	 */

	Dep.prototype.notify = function() {
		// stablize the subscriber list first
		var subs = toArray(this.subs);
		for(var i = 0, l = subs.length; i < l; i++) {
			subs[i].update();
		}
	};

	var arrayProto = Array.prototype;
	var arrayMethods = Object.create(arrayProto)

	/**
	 * Intercept mutating methods and emit events
	 */

	;
	['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function(method) {
		// cache original method
		var original = arrayProto[method];
		def(arrayMethods, method, function mutator() {
			// avoid leaking arguments:
			// http://jsperf.com/closure-with-arguments
			var i = arguments.length;
			var args = new Array(i);
			while(i--) {
				args[i] = arguments[i];
			}
			var result = original.apply(this, args);
			var ob = this.__ob__;
			var inserted;
			switch(method) {
				case 'push':
					inserted = args;
					break;
				case 'unshift':
					inserted = args;
					break;
				case 'splice':
					inserted = args.slice(2);
					break;
			}
			if(inserted) ob.observeArray(inserted);
			// notify change
			ob.dep.notify();
			return result;
		});
	});

	/**
	 * Swap the element at the given index with a new value
	 * and emits corresponding event.
	 *
	 * @param {Number} index
	 * @param {*} val
	 * @return {*} - replaced element
	 */

	def(arrayProto, '$set', function $set(index, val) {
		if(index >= this.length) {
			this.length = Number(index) + 1;
		}
		return this.splice(index, 1, val)[0];
	});

	/**
	 * Convenience method to remove the element at given index or target element reference.
	 *
	 * @param {*} item
	 */

	def(arrayProto, '$remove', function $remove(item) {
		/* istanbul ignore if */
		if(!this.length) return;
		var index = indexOf(this, item);
		if(index > -1) {
			return this.splice(index, 1);
		}
	});

	var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

	/**
	 * By default, when a reactive property is set, the new value is
	 * also converted to become reactive. However in certain cases, e.g.
	 * v-for scope alias and props, we don't want to force conversion
	 * because the value may be a nested value under a frozen data structure.
	 *
	 * So whenever we want to set a reactive property without forcing
	 * conversion on the new value, we wrap that call inside this function.
	 */

	var shouldConvert = true;

	function withoutConversion(fn) {
		shouldConvert = false;
		fn();
		shouldConvert = true;
	}

	/**
	 * Observer class that are attached to each observed
	 * object. Once attached, the observer converts target
	 * object's property keys into getter/setters that
	 * collect dependencies and dispatches updates.
	 *
	 * @param {Array|Object} value
	 * @constructor
	 */

	function Observer(value) {
		this.value = value;
		this.dep = new Dep();
		def(value, '__ob__', this);
		if(isArray(value)) {
			var augment = hasProto ? protoAugment : copyAugment;
			augment(value, arrayMethods, arrayKeys);
			this.observeArray(value);
		} else {
			this.walk(value);
		}
	}

	// Instance methods

	/**
	 * Walk through each property and convert them into
	 * getter/setters. This method should only be called when
	 * value type is Object.
	 *
	 * @param {Object} obj
	 */

	Observer.prototype.walk = function(obj) {
		var keys = Object.keys(obj);
		for(var i = 0, l = keys.length; i < l; i++) {
			this.convert(keys[i], obj[keys[i]]);
		}
	};

	/**
	 * Observe a list of Array items.
	 *
	 * @param {Array} items
	 */

	Observer.prototype.observeArray = function(items) {
		for(var i = 0, l = items.length; i < l; i++) {
			observe(items[i]);
		}
	};

	/**
	 * Convert a property into getter/setter so we can emit
	 * the events when the property is accessed/changed.
	 *
	 * @param {String} key
	 * @param {*} val
	 */

	Observer.prototype.convert = function(key, val) {
		defineReactive(this.value, key, val);
	};

	/**
	 * Add an owner vm, so that when $set/$delete mutations
	 * happen we can notify owner vms to proxy the keys and
	 * digest the watchers. This is only called when the object
	 * is observed as an instance's root $data.
	 *
	 * @param {Vue} vm
	 */

	Observer.prototype.addVm = function(vm) {
		(this.vms || (this.vms = [])).push(vm);
	};

	/**
	 * Remove an owner vm. This is called when the object is
	 * swapped out as an instance's $data object.
	 *
	 * @param {Vue} vm
	 */

	Observer.prototype.removeVm = function(vm) {
		this.vms.$remove(vm);
	};

	// helpers

	/**
	 * Augment an target Object or Array by intercepting
	 * the prototype chain using __proto__
	 *
	 * @param {Object|Array} target
	 * @param {Object} src
	 */

	function protoAugment(target, src) {
		/* eslint-disable no-proto */
		target.__proto__ = src;
		/* eslint-enable no-proto */
	}

	/**
	 * Augment an target Object or Array by defining
	 * hidden properties.
	 *
	 * @param {Object|Array} target
	 * @param {Object} proto
	 */

	function copyAugment(target, src, keys) {
		for(var i = 0, l = keys.length; i < l; i++) {
			var key = keys[i];
			def(target, key, src[key]);
		}
	}

	/**
	 * Attempt to create an observer instance for a value,
	 * returns the new observer if successfully observed,
	 * or the existing observer if the value already has one.
	 *
	 * @param {*} value
	 * @param {Vue} [vm]
	 * @return {Observer|undefined}
	 * @static
	 */

	function observe(value, vm) {
		if(!value || typeof value !== 'object') {
			return;
		}
		var ob;
		if(hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
			ob = value.__ob__;
		} else if(shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) {
			ob = new Observer(value);
		}
		if(ob && vm) {
			ob.addVm(vm);
		}
		return ob;
	}

	/**
	 * Define a reactive property on an Object.
	 *
	 * @param {Object} obj
	 * @param {String} key
	 * @param {*} val
	 */

	function defineReactive(obj, key, val) {
		var dep = new Dep();

		var property = Object.getOwnPropertyDescriptor(obj, key);
		if(property && property.configurable === false) {
			return;
		}

		// cater for pre-defined getter/setters
		var getter = property && property.get;
		var setter = property && property.set;

		var childOb = observe(val);
		Object.defineProperty(obj, key, {
			enumerable: true,
			configurable: true,
			get: function reactiveGetter() {
				var value = getter ? getter.call(obj) : val;
				if(Dep.target) {
					dep.depend();
					if(childOb) {
						childOb.dep.depend();
					}
					if(isArray(value)) {
						for(var e, i = 0, l = value.length; i < l; i++) {
							e = value[i];
							e && e.__ob__ && e.__ob__.dep.depend();
						}
					}
				}
				return value;
			},
			set: function reactiveSetter(newVal) {
				var value = getter ? getter.call(obj) : val;
				if(newVal === value) {
					return;
				}
				if(setter) {
					setter.call(obj, newVal);
				} else {
					val = newVal;
				}
				childOb = observe(newVal);
				dep.notify();
			}
		});
	}

	var util = Object.freeze({
		defineReactive: defineReactive,
		set: set,
		del: del,
		hasOwn: hasOwn,
		isLiteral: isLiteral,
		isReserved: isReserved,
		_toString: _toString,
		toNumber: toNumber,
		toBoolean: toBoolean,
		stripQuotes: stripQuotes,
		camelize: camelize,
		hyphenate: hyphenate,
		classify: classify,
		bind: bind,
		toArray: toArray,
		extend: extend,
		isObject: isObject,
		isPlainObject: isPlainObject,
		def: def,
		debounce: _debounce,
		indexOf: indexOf,
		cancellable: cancellable,
		looseEqual: looseEqual,
		isArray: isArray,
		hasProto: hasProto,
		inBrowser: inBrowser,
		devtools: devtools,
		isIE9: isIE9,
		isAndroid: isAndroid,
		isIos: isIos,
		isWechat: isWechat,
		get transitionProp() { return transitionProp; },
		get transitionEndEvent() { return transitionEndEvent; },
		get animationProp() { return animationProp; },
		get animationEndEvent() { return animationEndEvent; },
		nextTick: nextTick,
		get _Set() { return _Set; },
		query: query,
		inDoc: inDoc,
		getAttr: getAttr,
		getBindAttr: getBindAttr,
		hasBindAttr: hasBindAttr,
		before: before,
		after: after,
		remove: remove,
		prepend: prepend,
		replace: replace,
		on: on,
		off: off,
		setClass: setClass,
		addClass: addClass,
		removeClass: removeClass,
		extractContent: extractContent,
		trimNode: trimNode,
		isTemplate: isTemplate,
		createAnchor: createAnchor,
		findRef: findRef,
		mapNodeRange: mapNodeRange,
		removeNodeRange: removeNodeRange,
		isFragment: isFragment,
		getOuterHTML: getOuterHTML,
		mergeOptions: mergeOptions,
		resolveAsset: resolveAsset,
		checkComponentAttr: checkComponentAttr,
		commonTagRE: commonTagRE,
		reservedTagRE: reservedTagRE,
		get warn() { return warn; }
	});

	var uid = 0;

	function initMixin(Vue) {
		/**
		 * The main init sequence. This is called for every
		 * instance, including ones that are created from extended
		 * constructors.
		 *
		 * @param {Object} options - this options object should be
		 *                           the result of merging class
		 *                           options and the options passed
		 *                           in to the constructor.
		 */

		Vue.prototype._init = function(options) {
			options = options || {};

			this.$el = null;
			this.$parent = options.parent;
			this.$root = this.$parent ? this.$parent.$root : this;
			this.$children = [];
			this.$refs = {}; // child vm references
			this.$els = {}; // element references
			this._watchers = []; // all watchers as an array
			this._directives = []; // all directives

			// a uid
			this._uid = uid++;

			// a flag to avoid this being observed
			this._isVue = true;

			// events bookkeeping
			this._events = {}; // registered callbacks
			this._eventsCount = {}; // for $broadcast optimization

			// fragment instance properties
			this._isFragment = false;
			this._fragment = // @type {DocumentFragment}
				this._fragmentStart = // @type {Text|Comment}
				this._fragmentEnd = null; // @type {Text|Comment}

			// lifecycle state
			this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false;
			this._unlinkFn = null;

			// context:
			// if this is a transcluded component, context
			// will be the common parent vm of this instance
			// and its host.
			this._context = options._context || this.$parent;

			// scope:
			// if this is inside an inline v-for, the scope
			// will be the intermediate scope created for this
			// repeat fragment. this is used for linking props
			// and container directives.
			this._scope = options._scope;

			// fragment:
			// if this instance is compiled inside a Fragment, it
			// needs to reigster itself as a child of that fragment
			// for attach/detach to work properly.
			this._frag = options._frag;
			if(this._frag) {
				this._frag.children.push(this);
			}

			// push self into parent / transclusion host
			if(this.$parent) {
				this.$parent.$children.push(this);
			}

			// merge options.
			options = this.$options = mergeOptions(this.constructor.options, options, this);

			// set ref
			this._updateRef();

			// initialize data as empty object.
			// it will be filled up in _initData().
			this._data = {};

			// call init hook
			this._callHook('init');

			// initialize data observation and scope inheritance.
			this._initState();

			// setup event system and option events.
			this._initEvents();

			// call created hook
			this._callHook('created');

			// if `el` option is passed, start compilation.
			if(options.el) {
				this.$mount(options.el);
			}
		};
	}

	var pathCache = new Cache(1000);

	// actions
	var APPEND = 0;
	var PUSH = 1;
	var INC_SUB_PATH_DEPTH = 2;
	var PUSH_SUB_PATH = 3;

	// states
	var BEFORE_PATH = 0;
	var IN_PATH = 1;
	var BEFORE_IDENT = 2;
	var IN_IDENT = 3;
	var IN_SUB_PATH = 4;
	var IN_SINGLE_QUOTE = 5;
	var IN_DOUBLE_QUOTE = 6;
	var AFTER_PATH = 7;
	var ERROR = 8;

	var pathStateMachine = [];

	pathStateMachine[BEFORE_PATH] = {
		'ws': [BEFORE_PATH],
		'ident': [IN_IDENT, APPEND],
		'[': [IN_SUB_PATH],
		'eof': [AFTER_PATH]
	};

	pathStateMachine[IN_PATH] = {
		'ws': [IN_PATH],
		'.': [BEFORE_IDENT],
		'[': [IN_SUB_PATH],
		'eof': [AFTER_PATH]
	};

	pathStateMachine[BEFORE_IDENT] = {
		'ws': [BEFORE_IDENT],
		'ident': [IN_IDENT, APPEND]
	};

	pathStateMachine[IN_IDENT] = {
		'ident': [IN_IDENT, APPEND],
		'0': [IN_IDENT, APPEND],
		'number': [IN_IDENT, APPEND],
		'ws': [IN_PATH, PUSH],
		'.': [BEFORE_IDENT, PUSH],
		'[': [IN_SUB_PATH, PUSH],
		'eof': [AFTER_PATH, PUSH]
	};

	pathStateMachine[IN_SUB_PATH] = {
		"'": [IN_SINGLE_QUOTE, APPEND],
		'"': [IN_DOUBLE_QUOTE, APPEND],
		'[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
		']': [IN_PATH, PUSH_SUB_PATH],
		'eof': ERROR,
		'else': [IN_SUB_PATH, APPEND]
	};

	pathStateMachine[IN_SINGLE_QUOTE] = {
		"'": [IN_SUB_PATH, APPEND],
		'eof': ERROR,
		'else': [IN_SINGLE_QUOTE, APPEND]
	};

	pathStateMachine[IN_DOUBLE_QUOTE] = {
		'"': [IN_SUB_PATH, APPEND],
		'eof': ERROR,
		'else': [IN_DOUBLE_QUOTE, APPEND]
	};

	/**
	 * Determine the type of a character in a keypath.
	 *
	 * @param {Char} ch
	 * @return {String} type
	 */

	function getPathCharType(ch) {
		if(ch === undefined) {
			return 'eof';
		}

		var code = ch.charCodeAt(0);

		switch(code) {
			case 0x5B: // [
			case 0x5D: // ]
			case 0x2E: // .
			case 0x22: // "
			case 0x27: // '
			case 0x30:
				// 0
				return ch;

			case 0x5F: // _
			case 0x24:
				// $
				return 'ident';

			case 0x20: // Space
			case 0x09: // Tab
			case 0x0A: // Newline
			case 0x0D: // Return
			case 0xA0: // No-break space
			case 0xFEFF: // Byte Order Mark
			case 0x2028: // Line Separator
			case 0x2029:
				// Paragraph Separator
				return 'ws';
		}

		// a-z, A-Z
		if(code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) {
			return 'ident';
		}

		// 1-9
		if(code >= 0x31 && code <= 0x39) {
			return 'number';
		}

		return 'else';
	}

	/**
	 * Format a subPath, return its plain form if it is
	 * a literal string or number. Otherwise prepend the
	 * dynamic indicator (*).
	 *
	 * @param {String} path
	 * @return {String}
	 */

	function formatSubPath(path) {
		var trimmed = path.trim();
		// invalid leading 0
		if(path.charAt(0) === '0' && isNaN(path)) {
			return false;
		}
		return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed;
	}

	/**
	 * Parse a string path into an array of segments
	 *
	 * @param {String} path
	 * @return {Array|undefined}
	 */

	function parse(path) {
		var keys = [];
		var index = -1;
		var mode = BEFORE_PATH;
		var subPathDepth = 0;
		var c, newChar, key, type, transition, action, typeMap;

		var actions = [];

		actions[PUSH] = function() {
			if(key !== undefined) {
				keys.push(key);
				key = undefined;
			}
		};

		actions[APPEND] = function() {
			if(key === undefined) {
				key = newChar;
			} else {
				key += newChar;
			}
		};

		actions[INC_SUB_PATH_DEPTH] = function() {
			actions[APPEND]();
			subPathDepth++;
		};

		actions[PUSH_SUB_PATH] = function() {
			if(subPathDepth > 0) {
				subPathDepth--;
				mode = IN_SUB_PATH;
				actions[APPEND]();
			} else {
				subPathDepth = 0;
				key = formatSubPath(key);
				if(key === false) {
					return false;
				} else {
					actions[PUSH]();
				}
			}
		};

		function maybeUnescapeQuote() {
			var nextChar = path[index + 1];
			if(mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') {
				index++;
				newChar = '\\' + nextChar;
				actions[APPEND]();
				return true;
			}
		}

		while(mode != null) {
			index++;
			c = path[index];

			if(c === '\\' && maybeUnescapeQuote()) {
				continue;
			}

			type = getPathCharType(c);
			typeMap = pathStateMachine[mode];
			transition = typeMap[type] || typeMap['else'] || ERROR;

			if(transition === ERROR) {
				return; // parse error
			}

			mode = transition[0];
			action = actions[transition[1]];
			if(action) {
				newChar = transition[2];
				newChar = newChar === undefined ? c : newChar;
				if(action() === false) {
					return;
				}
			}

			if(mode === AFTER_PATH) {
				keys.raw = path;
				return keys;
			}
		}
	}

	/**
	 * External parse that check for a cache hit first
	 *
	 * @param {String} path
	 * @return {Array|undefined}
	 */

	function parsePath(path) {
		var hit = pathCache.get(path);
		if(!hit) {
			hit = parse(path);
			if(hit) {
				pathCache.put(path, hit);
			}
		}
		return hit;
	}

	/**
	 * Get from an object from a path string
	 *
	 * @param {Object} obj
	 * @param {String} path
	 */

	function getPath(obj, path) {
		return parseExpression(path).get(obj);
	}

	/**
	 * Warn against setting non-existent root path on a vm.
	 */

	var warnNonExistent;
	if('development' !== 'production') {
		warnNonExistent = function(path, vm) {
			warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm);
		};
	}

	/**
	 * Set on an object from a path
	 *
	 * @param {Object} obj
	 * @param {String | Array} path
	 * @param {*} val
	 */

	function setPath(obj, path, val) {
		var original = obj;
		if(typeof path === 'string') {
			path = parse(path);
		}
		if(!path || !isObject(obj)) {
			return false;
		}
		var last, key;
		for(var i = 0, l = path.length; i < l; i++) {
			last = obj;
			key = path[i];
			if(key.charAt(0) === '*') {
				key = parseExpression(key.slice(1)).get.call(original, original);
			}
			if(i < l - 1) {
				obj = obj[key];
				if(!isObject(obj)) {
					obj = {};
					if('development' !== 'production' && last._isVue) {
						warnNonExistent(path, last);
					}
					set(last, key, obj);
				}
			} else {
				if(isArray(obj)) {
					obj.$set(key, val);
				} else if(key in obj) {
					obj[key] = val;
				} else {
					if('development' !== 'production' && obj._isVue) {
						warnNonExistent(path, obj);
					}
					set(obj, key, val);
				}
			}
		}
		return true;
	}

	var path = Object.freeze({
		parsePath: parsePath,
		getPath: getPath,
		setPath: setPath
	});

	var expressionCache = new Cache(1000);

	var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat';
	var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)');

	// keywords that don't make sense inside expressions
	var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public';
	var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)');

	var wsRE = /\s/g;
	var newlineRE = /\n/g;
	var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g;
	var restoreRE = /"(\d+)"/g;
	var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/;
	var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g;
	var booleanLiteralRE = /^(?:true|false)$/;

	/**
	 * Save / Rewrite / Restore
	 *
	 * When rewriting paths found in an expression, it is
	 * possible for the same letter sequences to be found in
	 * strings and Object literal property keys. Therefore we
	 * remove and store these parts in a temporary array, and
	 * restore them after the path rewrite.
	 */

	var saved = [];

	/**
	 * Save replacer
	 *
	 * The save regex can match two possible cases:
	 * 1. An opening object literal
	 * 2. A string
	 * If matched as a plain string, we need to escape its
	 * newlines, since the string needs to be preserved when
	 * generating the function body.
	 *
	 * @param {String} str
	 * @param {String} isString - str if matched as a string
	 * @return {String} - placeholder with index
	 */

	function save(str, isString) {
		var i = saved.length;
		saved[i] = isString ? str.replace(newlineRE, '\\n') : str;
		return '"' + i + '"';
	}

	/**
	 * Path rewrite replacer
	 *
	 * @param {String} raw
	 * @return {String}
	 */

	function rewrite(raw) {
		var c = raw.charAt(0);
		var path = raw.slice(1);
		if(allowedKeywordsRE.test(path)) {
			return raw;
		} else {
			path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path;
			return c + 'scope.' + path;
		}
	}

	/**
	 * Restore replacer
	 *
	 * @param {String} str
	 * @param {String} i - matched save index
	 * @return {String}
	 */

	function restore(str, i) {
		return saved[i];
	}

	/**
	 * Rewrite an expression, prefixing all path accessors with
	 * `scope.` and generate getter/setter functions.
	 *
	 * @param {String} exp
	 * @return {Function}
	 */

	function compileGetter(exp) {
		if(improperKeywordsRE.test(exp)) {
			'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp);
		}
		// reset state
		saved.length = 0;
		// save strings and object literal keys
		var body = exp.replace(saveRE, save).replace(wsRE, '');
		// rewrite all paths
		// pad 1 space here becaue the regex matches 1 extra char
		body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore);
		return makeGetterFn(body);
	}

	/**
	 * Build a getter function. Requires eval.
	 *
	 * We isolate the try/catch so it doesn't affect the
	 * optimization of the parse function when it is not called.
	 *
	 * @param {String} body
	 * @return {Function|undefined}
	 */

	function makeGetterFn(body) {
		try {
			/* eslint-disable no-new-func */
			return new Function('scope', 'return ' + body + ';');
			/* eslint-enable no-new-func */
		} catch(e) {
			'development' !== 'production' && warn('Invalid expression. ' + 'Generated function body: ' + body);
		}
	}

	/**
	 * Compile a setter function for the expression.
	 *
	 * @param {String} exp
	 * @return {Function|undefined}
	 */

	function compileSetter(exp) {
		var path = parsePath(exp);
		if(path) {
			return function(scope, val) {
				setPath(scope, path, val);
			};
		} else {
			'development' !== 'production' && warn('Invalid setter expression: ' + exp);
		}
	}

	/**
	 * Parse an expression into re-written getter/setters.
	 *
	 * @param {String} exp
	 * @param {Boolean} needSet
	 * @return {Function}
	 */

	function parseExpression(exp, needSet) {
		exp = exp.trim();
		// try cache
		var hit = expressionCache.get(exp);
		if(hit) {
			if(needSet && !hit.set) {
				hit.set = compileSetter(hit.exp);
			}
			return hit;
		}
		var res = { exp: exp };
		res.get = isSimplePath(exp) && exp.indexOf('[') < 0
			// optimized super simple getter
			?
			makeGetterFn('scope.' + exp)
			// dynamic getter
			:
			compileGetter(exp);
		if(needSet) {
			res.set = compileSetter(exp);
		}
		expressionCache.put(exp, res);
		return res;
	}

	/**
	 * Check if an expression is a simple path.
	 *
	 * @param {String} exp
	 * @return {Boolean}
	 */

	function isSimplePath(exp) {
		return pathTestRE.test(exp) &&
			// don't treat true/false as paths
			!booleanLiteralRE.test(exp) &&
			// Math constants e.g. Math.PI, Math.E etc.
			exp.slice(0, 5) !== 'Math.';
	}

	var expression = Object.freeze({
		parseExpression: parseExpression,
		isSimplePath: isSimplePath
	});

	// we have two separate queues: one for directive updates
	// and one for user watcher registered via $watch().
	// we want to guarantee directive updates to be called
	// before user watchers so that when user watchers are
	// triggered, the DOM would have already been in updated
	// state.

	var queue = [];
	var userQueue = [];
	var has = {};
	var circular = {};
	var waiting = false;

	/**
	 * Reset the batcher's state.
	 */

	function resetBatcherState() {
		queue.length = 0;
		userQueue.length = 0;
		has = {};
		circular = {};
		waiting = false;
	}

	/**
	 * Flush both queues and run the watchers.
	 */

	function flushBatcherQueue() {
		var _again = true;

		_function: while(_again) {
			_again = false;

			runBatcherQueue(queue);
			runBatcherQueue(userQueue);
			// user watchers triggered more watchers,
			// keep flushing until it depletes
			if(queue.length) {
				_again = true;
				continue _function;
			}
			// dev tool hook
			/* istanbul ignore if */
			if(devtools && config.devtools) {
				devtools.emit('flush');
			}
			resetBatcherState();
		}
	}

	/**
	 * Run the watchers in a single queue.
	 *
	 * @param {Array} queue
	 */

	function runBatcherQueue(queue) {
		// do not cache length because more watchers might be pushed
		// as we run existing watchers
		for(var i = 0; i < queue.length; i++) {
			var watcher = queue[i];
			var id = watcher.id;
			has[id] = null;
			watcher.run();
			// in dev build, check and stop circular updates.
			if('development' !== 'production' && has[id] != null) {
				circular[id] = (circular[id] || 0) + 1;
				if(circular[id] > config._maxUpdateCount) {
					warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm);
					break;
				}
			}
		}
		queue.length = 0;
	}

	/**
	 * Push a watcher into the watcher queue.
	 * Jobs with duplicate IDs will be skipped unless it's
	 * pushed when the queue is being flushed.
	 *
	 * @param {Watcher} watcher
	 *   properties:
	 *   - {Number} id
	 *   - {Function} run
	 */

	function pushWatcher(watcher) {
		var id = watcher.id;
		if(has[id] == null) {
			// push watcher into appropriate queue
			var q = watcher.user ? userQueue : queue;
			has[id] = q.length;
			q.push(watcher);
			// queue the flush
			if(!waiting) {
				waiting = true;
				nextTick(flushBatcherQueue);
			}
		}
	}

	var uid$2 = 0;

	/**
	 * A watcher parses an expression, collects dependencies,
	 * and fires callback when the expression value changes.
	 * This is used for both the $watch() api and directives.
	 *
	 * @param {Vue} vm
	 * @param {String|Function} expOrFn
	 * @param {Function} cb
	 * @param {Object} options
	 *                 - {Array} filters
	 *                 - {Boolean} twoWay
	 *                 - {Boolean} deep
	 *                 - {Boolean} user
	 *                 - {Boolean} sync
	 *                 - {Boolean} lazy
	 *                 - {Function} [preProcess]
	 *                 - {Function} [postProcess]
	 * @constructor
	 */
	function Watcher(vm, expOrFn, cb, options) {
		// mix in options
		if(options) {
			extend(this, options);
		}
		var isFn = typeof expOrFn === 'function';
		this.vm = vm;
		vm._watchers.push(this);
		this.expression = expOrFn;
		this.cb = cb;
		this.id = ++uid$2; // uid for batching
		this.active = true;
		this.dirty = this.lazy; // for lazy watchers
		this.deps = [];
		this.newDeps = [];
		this.depIds = new _Set();
		this.newDepIds = new _Set();
		this.prevError = null; // for async error stacks
		// parse expression for getter/setter
		if(isFn) {
			this.getter = expOrFn;
			this.setter = undefined;
		} else {
			var res = parseExpression(expOrFn, this.twoWay);
			this.getter = res.get;
			this.setter = res.set;
		}
		this.value = this.lazy ? undefined : this.get();
		// state for avoiding false triggers for deep and Array
		// watchers during vm._digest()
		this.queued = this.shallow = false;
	}

	/**
	 * Evaluate the getter, and re-collect dependencies.
	 */

	Watcher.prototype.get = function() {
		this.beforeGet();
		var scope = this.scope || this.vm;
		var value;
		try {
			value = this.getter.call(scope, scope);
		} catch(e) {
			if('development' !== 'production' && config.warnExpressionErrors) {
				warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm);
			}
		}
		// "touch" every property so they are all tracked as
		// dependencies for deep watching
		if(this.deep) {
			traverse(value);
		}
		if(this.preProcess) {
			value = this.preProcess(value);
		}
		if(this.filters) {
			value = scope._applyFilters(value, null, this.filters, false);
		}
		if(this.postProcess) {
			value = this.postProcess(value);
		}
		this.afterGet();
		return value;
	};

	/**
	 * Set the corresponding value with the setter.
	 *
	 * @param {*} value
	 */

	Watcher.prototype.set = function(value) {
		var scope = this.scope || this.vm;
		if(this.filters) {
			value = scope._applyFilters(value, this.value, this.filters, true);
		}
		try {
			this.setter.call(scope, scope, value);
		} catch(e) {
			if('development' !== 'production' && config.warnExpressionErrors) {
				warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm);
			}
		}
		// two-way sync for v-for alias
		var forContext = scope.$forContext;
		if(forContext && forContext.alias === this.expression) {
			if(forContext.filters) {
				'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm);
				return;
			}
			forContext._withLock(function() {
				if(scope.$key) {
					// original is an object
					forContext.rawValue[scope.$key] = value;
				} else {
					forContext.rawValue.$set(scope.$index, value);
				}
			});
		}
	};

	/**
	 * Prepare for dependency collection.
	 */

	Watcher.prototype.beforeGet = function() {
		Dep.target = this;
	};

	/**
	 * Add a dependency to this directive.
	 *
	 * @param {Dep} dep
	 */

	Watcher.prototype.addDep = function(dep) {
		var id = dep.id;
		if(!this.newDepIds.has(id)) {
			this.newDepIds.add(id);
			this.newDeps.push(dep);
			if(!this.depIds.has(id)) {
				dep.addSub(this);
			}
		}
	};

	/**
	 * Clean up for dependency collection.
	 */

	Watcher.prototype.afterGet = function() {
		Dep.target = null;
		var i = this.deps.length;
		while(i--) {
			var dep = this.deps[i];
			if(!this.newDepIds.has(dep.id)) {
				dep.removeSub(this);
			}
		}
		var tmp = this.depIds;
		this.depIds = this.newDepIds;
		this.newDepIds = tmp;
		this.newDepIds.clear();
		tmp = this.deps;
		this.deps = this.newDeps;
		this.newDeps = tmp;
		this.newDeps.length = 0;
	};

	/**
	 * Subscriber interface.
	 * Will be called when a dependency changes.
	 *
	 * @param {Boolean} shallow
	 */

	Watcher.prototype.update = function(shallow) {
		if(this.lazy) {
			this.dirty = true;
		} else if(this.sync || !config.async) {
			this.run();
		} else {
			// if queued, only overwrite shallow with non-shallow,
			// but not the other way around.
			this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow;
			this.queued = true;
			// record before-push error stack in debug mode
			/* istanbul ignore if */
			if('development' !== 'production' && config.debug) {
				this.prevError = new Error('[vue] async stack trace');
			}
			pushWatcher(this);
		}
	};

	/**
	 * Batcher job interface.
	 * Will be called by the batcher.
	 */

	Watcher.prototype.run = function() {
		if(this.active) {
			var value = this.get();
			if(value !== this.value ||
				// Deep watchers and watchers on Object/Arrays should fire even
				// when the value is the same, because the value may
				// have mutated; but only do so if this is a
				// non-shallow update (caused by a vm digest).
				(isObject(value) || this.deep) && !this.shallow) {
				// set new value
				var oldValue = this.value;
				this.value = value;
				// in debug + async mode, when a watcher callbacks
				// throws, we also throw the saved before-push error
				// so the full cross-tick stack trace is available.
				var prevError = this.prevError;
				/* istanbul ignore if */
				if('development' !== 'production' && config.debug && prevError) {
					this.prevError = null;
					try {
						this.cb.call(this.vm, value, oldValue);
					} catch(e) {
						nextTick(function() {
							throw prevError;
						}, 0);
						throw e;
					}
				} else {
					this.cb.call(this.vm, value, oldValue);
				}
			}
			this.queued = this.shallow = false;
		}
	};

	/**
	 * Evaluate the value of the watcher.
	 * This only gets called for lazy watchers.
	 */

	Watcher.prototype.evaluate = function() {
		// avoid overwriting another watcher that is being
		// collected.
		var current = Dep.target;
		this.value = this.get();
		this.dirty = false;
		Dep.target = current;
	};

	/**
	 * Depend on all deps collected by this watcher.
	 */

	Watcher.prototype.depend = function() {
		var i = this.deps.length;
		while(i--) {
			this.deps[i].depend();
		}
	};

	/**
	 * Remove self from all dependencies' subcriber list.
	 */

	Watcher.prototype.teardown = function() {
		if(this.active) {
			// remove self from vm's watcher list
			// this is a somewhat expensive operation so we skip it
			// if the vm is being destroyed or is performing a v-for
			// re-render (the watcher list is then filtered by v-for).
			if(!this.vm._isBeingDestroyed && !this.vm._vForRemoving) {
				this.vm._watchers.$remove(this);
			}
			var i = this.deps.length;
			while(i--) {
				this.deps[i].removeSub(this);
			}
			this.active = false;
			this.vm = this.cb = this.value = null;
		}
	};

	/**
	 * Recrusively traverse an object to evoke all converted
	 * getters, so that every nested property inside the object
	 * is collected as a "deep" dependency.
	 *
	 * @param {*} val
	 */

	var seenObjects = new _Set();

	function traverse(val, seen) {
		var i = undefined,
			keys = undefined;
		if(!seen) {
			seen = seenObjects;
			seen.clear();
		}
		var isA = isArray(val);
		var isO = isObject(val);
		if(isA || isO) {
			if(val.__ob__) {
				var depId = val.__ob__.dep.id;
				if(seen.has(depId)) {
					return;
				} else {
					seen.add(depId);
				}
			}
			if(isA) {
				i = val.length;
				while(i--) traverse(val[i], seen);
			} else if(isO) {
				keys = Object.keys(val);
				i = keys.length;
				while(i--) traverse(val[keys[i]], seen);
			}
		}
	}

	var text$1 = {

		bind: function bind() {
			this.attr = this.el.nodeType === 3 ? 'data' : 'textContent';
		},

		update: function update(value) {
			this.el[this.attr] = _toString(value);
		}
	};

	var templateCache = new Cache(1000);
	var idSelectorCache = new Cache(1000);

	var map = {
		efault: [0, '', ''],
		legend: [1, '<fieldset>', '</fieldset>'],
		tr: [2, '<table><tbody>', '</tbody></table>'],
		col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>']
	};

	map.td = map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];

	map.option = map.optgroup = [1, '<select multiple="multiple">', '</select>'];

	map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '<table>', '</table>'];

	map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '<svg ' + 'xmlns="http://www.w3.org/2000/svg" ' + 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + 'xmlns:ev="http://www.w3.org/2001/xml-events"' + 'version="1.1">', '</svg>'];

	/**
	 * Check if a node is a supported template node with a
	 * DocumentFragment content.
	 *
	 * @param {Node} node
	 * @return {Boolean}
	 */

	function isRealTemplate(node) {
		return isTemplate(node) && isFragment(node.content);
	}

	var tagRE$1 = /<([\w:-]+)/;
	var entityRE = /&#?\w+?;/;

	/**
	 * Convert a string template to a DocumentFragment.
	 * Determines correct wrapping by tag types. Wrapping
	 * strategy found in jQuery & component/domify.
	 *
	 * @param {String} templateString
	 * @param {Boolean} raw
	 * @return {DocumentFragment}
	 */

	function stringToFragment(templateString, raw) {
		// try a cache hit first
		var cacheKey = raw ? templateString : templateString.trim();
		var hit = templateCache.get(cacheKey);
		if(hit) {
			return hit;
		}

		var frag = document.createDocumentFragment();
		var tagMatch = templateString.match(tagRE$1);
		var entityMatch = entityRE.test(templateString);

		if(!tagMatch && !entityMatch) {
			// text only, return a single text node.
			frag.appendChild(document.createTextNode(templateString));
		} else {
			var tag = tagMatch && tagMatch[1];
			var wrap = map[tag] || map.efault;
			var depth = wrap[0];
			var prefix = wrap[1];
			var suffix = wrap[2];
			var node = document.createElement('div');

			node.innerHTML = prefix + templateString + suffix;
			while(depth--) {
				node = node.lastChild;
			}

			var child;
			/* eslint-disable no-cond-assign */
			while(child = node.firstChild) {
				/* eslint-enable no-cond-assign */
				frag.appendChild(child);
			}
		}
		if(!raw) {
			trimNode(frag);
		}
		templateCache.put(cacheKey, frag);
		return frag;
	}

	/**
	 * Convert a template node to a DocumentFragment.
	 *
	 * @param {Node} node
	 * @return {DocumentFragment}
	 */

	function nodeToFragment(node) {
		// if its a template tag and the browser supports it,
		// its content is already a document fragment. However, iOS Safari has
		// bug when using directly cloned template content with touch
		// events and can cause crashes when the nodes are removed from DOM, so we
		// have to treat template elements as string templates. (#2805)
		/* istanbul ignore if */
		if(isRealTemplate(node)) {
			return stringToFragment(node.innerHTML);
		}
		// script template
		if(node.tagName === 'SCRIPT') {
			return stringToFragment(node.textContent);
		}
		// normal node, clone it to avoid mutating the original
		var clonedNode = cloneNode(node);
		var frag = document.createDocumentFragment();
		var child;
		/* eslint-disable no-cond-assign */
		while(child = clonedNode.firstChild) {
			/* eslint-enable no-cond-assign */
			frag.appendChild(child);
		}
		trimNode(frag);
		return frag;
	}

	// Test for the presence of the Safari template cloning bug
	// https://bugs.webkit.org/showug.cgi?id=137755
	var hasBrokenTemplate = (function() {
		/* istanbul ignore else */
		if(inBrowser) {
			var a = document.createElement('div');
			a.innerHTML = '<template>1</template>';
			return !a.cloneNode(true).firstChild.innerHTML;
		} else {
			return false;
		}
	})();

	// Test for IE10/11 textarea placeholder clone bug
	var hasTextareaCloneBug = (function() {
		/* istanbul ignore else */
		if(inBrowser) {
			var t = document.createElement('textarea');
			t.placeholder = 't';
			return t.cloneNode(true).value === 't';
		} else {
			return false;
		}
	})();

	/**
	 * 1. Deal with Safari cloning nested <template> bug by
	 *    manually cloning all template instances.
	 * 2. Deal with IE10/11 textarea placeholder bug by setting
	 *    the correct value after cloning.
	 *
	 * @param {Element|DocumentFragment} node
	 * @return {Element|DocumentFragment}
	 */

	function cloneNode(node) {
		/* istanbul ignore if */
		if(!node.querySelectorAll) {
			return node.cloneNode();
		}
		var res = node.cloneNode(true);
		var i, original, cloned;
		/* istanbul ignore if */
		if(hasBrokenTemplate) {
			var tempClone = res;
			if(isRealTemplate(node)) {
				node = node.content;
				tempClone = res.content;
			}
			original = node.querySelectorAll('template');
			if(original.length) {
				cloned = tempClone.querySelectorAll('template');
				i = cloned.length;
				while(i--) {
					cloned[i].parentNode.replaceChild(cloneNode(original[i]), cloned[i]);
				}
			}
		}
		/* istanbul ignore if */
		if(hasTextareaCloneBug) {
			if(node.tagName === 'TEXTAREA') {
				res.value = node.value;
			} else {
				original = node.querySelectorAll('textarea');
				if(original.length) {
					cloned = res.querySelectorAll('textarea');
					i = cloned.length;
					while(i--) {
						cloned[i].value = original[i].value;
					}
				}
			}
		}
		return res;
	}

	/**
	 * Process the template option and normalizes it into a
	 * a DocumentFragment that can be used as a partial or a
	 * instance template.
	 *
	 * @param {*} template
	 *        Possible values include:
	 *        - DocumentFragment object
	 *        - Node object of type Template
	 *        - id selector: '#some-template-id'
	 *        - template string: '<div><span>{{msg}}</span></div>'
	 * @param {Boolean} shouldClone
	 * @param {Boolean} raw
	 *        inline HTML interpolation. Do not check for id
	 *        selector and keep whitespace in the string.
	 * @return {DocumentFragment|undefined}
	 */

	function parseTemplate(template, shouldClone, raw) {
		var node, frag;

		// if the template is already a document fragment,
		// do nothing
		if(isFragment(template)) {
			trimNode(template);
			return shouldClone ? cloneNode(template) : template;
		}

		if(typeof template === 'string') {
			// id selector
			if(!raw && template.charAt(0) === '#') {
				// id selector can be cached too
				frag = idSelectorCache.get(template);
				if(!frag) {
					node = document.getElementById(template.slice(1));
					if(node) {
						frag = nodeToFragment(node);
						// save selector to cache
						idSelectorCache.put(template, frag);
					}
				}
			} else {
				// normal string template
				frag = stringToFragment(template, raw);
			}
		} else if(template.nodeType) {
			// a direct node
			frag = nodeToFragment(template);
		}

		return frag && shouldClone ? cloneNode(frag) : frag;
	}

	var template = Object.freeze({
		cloneNode: cloneNode,
		parseTemplate: parseTemplate
	});

	var html = {

		bind: function bind() {
			// a comment node means this is a binding for
			// {{{ inline unescaped html }}}
			if(this.el.nodeType === 8) {
				// hold nodes
				this.nodes = [];
				// replace the placeholder with proper anchor
				this.anchor = createAnchor('v-html');
				replace(this.el, this.anchor);
			}
		},

		update: function update(value) {
			value = _toString(value);
			if(this.nodes) {
				this.swap(value);
			} else {
				this.el.innerHTML = value;
			}
		},

		swap: function swap(value) {
			// remove old nodes
			var i = this.nodes.length;
			while(i--) {
				remove(this.nodes[i]);
			}
			// convert new value to a fragment
			// do not attempt to retrieve from id selector
			var frag = parseTemplate(value, true, true);
			// save a reference to these nodes so we can remove later
			this.nodes = toArray(frag.childNodes);
			before(frag, this.anchor);
		}
	};

	/**
	 * Abstraction for a partially-compiled fragment.
	 * Can optionally compile content with a child scope.
	 *
	 * @param {Function} linker
	 * @param {Vue} vm
	 * @param {DocumentFragment} frag
	 * @param {Vue} [host]
	 * @param {Object} [scope]
	 * @param {Fragment} [parentFrag]
	 */
	function Fragment(linker, vm, frag, host, scope, parentFrag) {
		this.children = [];
		this.childFrags = [];
		this.vm = vm;
		this.scope = scope;
		this.inserted = false;
		this.parentFrag = parentFrag;
		if(parentFrag) {
			parentFrag.childFrags.push(this);
		}
		this.unlink = linker(vm, frag, host, scope, this);
		var single = this.single = frag.childNodes.length === 1 &&
			// do not go single mode if the only node is an anchor
			!frag.childNodes[0].__v_anchor;
		if(single) {
			this.node = frag.childNodes[0];
			this.before = singleBefore;
			this.remove = singleRemove;
		} else {
			this.node = createAnchor('fragment-start');
			this.end = createAnchor('fragment-end');
			this.frag = frag;
			prepend(this.node, frag);
			frag.appendChild(this.end);
			this.before = multiBefore;
			this.remove = multiRemove;
		}
		this.node.__v_frag = this;
	}

	/**
	 * Call attach/detach for all components contained within
	 * this fragment. Also do so recursively for all child
	 * fragments.
	 *
	 * @param {Function} hook
	 */

	Fragment.prototype.callHook = function(hook) {
		var i, l;
		for(i = 0, l = this.childFrags.length; i < l; i++) {
			this.childFrags[i].callHook(hook);
		}
		for(i = 0, l = this.children.length; i < l; i++) {
			hook(this.children[i]);
		}
	};

	/**
	 * Insert fragment before target, single node version
	 *
	 * @param {Node} target
	 * @param {Boolean} withTransition
	 */

	function singleBefore(target, withTransition) {
		this.inserted = true;
		var method = withTransition !== false ? beforeWithTransition : before;
		method(this.node, target, this.vm);
		if(inDoc(this.node)) {
			this.callHook(attach);
		}
	}

	/**
	 * Remove fragment, single node version
	 */

	function singleRemove() {
		this.inserted = false;
		var shouldCallRemove = inDoc(this.node);
		var self = this;
		this.beforeRemove();
		removeWithTransition(this.node, this.vm, function() {
			if(shouldCallRemove) {
				self.callHook(detach);
			}
			self.destroy();
		});
	}

	/**
	 * Insert fragment before target, multi-nodes version
	 *
	 * @param {Node} target
	 * @param {Boolean} withTransition
	 */

	function multiBefore(target, withTransition) {
		this.inserted = true;
		var vm = this.vm;
		var method = withTransition !== false ? beforeWithTransition : before;
		mapNodeRange(this.node, this.end, function(node) {
			method(node, target, vm);
		});
		if(inDoc(this.node)) {
			this.callHook(attach);
		}
	}

	/**
	 * Remove fragment, multi-nodes version
	 */

	function multiRemove() {
		this.inserted = false;
		var self = this;
		var shouldCallRemove = inDoc(this.node);
		this.beforeRemove();
		removeNodeRange(this.node, this.end, this.vm, this.frag, function() {
			if(shouldCallRemove) {
				self.callHook(detach);
			}
			self.destroy();
		});
	}

	/**
	 * Prepare the fragment for removal.
	 */

	Fragment.prototype.beforeRemove = function() {
		var i, l;
		for(i = 0, l = this.childFrags.length; i < l; i++) {
			// call the same method recursively on child
			// fragments, depth-first
			this.childFrags[i].beforeRemove(false);
		}
		for(i = 0, l = this.children.length; i < l; i++) {
			// Call destroy for all contained instances,
			// with remove:false and defer:true.
			// Defer is necessary because we need to
			// keep the children to call detach hooks
			// on them.
			this.children[i].$destroy(false, true);
		}
		var dirs = this.unlink.dirs;
		for(i = 0, l = dirs.length; i < l; i++) {
			// disable the watchers on all the directives
			// so that the rendered content stays the same
			// during removal.
			dirs[i]._watcher && dirs[i]._watcher.teardown();
		}
	};

	/**
	 * Destroy the fragment.
	 */

	Fragment.prototype.destroy = function() {
		if(this.parentFrag) {
			this.parentFrag.childFrags.$remove(this);
		}
		this.node.__v_frag = null;
		this.unlink();
	};

	/**
	 * Call attach hook for a Vue instance.
	 *
	 * @param {Vue} child
	 */

	function attach(child) {
		if(!child._isAttached && inDoc(child.$el)) {
			child._callHook('attached');
		}
	}

	/**
	 * Call detach hook for a Vue instance.
	 *
	 * @param {Vue} child
	 */

	function detach(child) {
		if(child._isAttached && !inDoc(child.$el)) {
			child._callHook('detached');
		}
	}

	var linkerCache = new Cache(5000);

	/**
	 * A factory that can be used to create instances of a
	 * fragment. Caches the compiled linker if possible.
	 *
	 * @param {Vue} vm
	 * @param {Element|String} el
	 */
	function FragmentFactory(vm, el) {
		this.vm = vm;
		var template;
		var isString = typeof el === 'string';
		if(isString || isTemplate(el) && !el.hasAttribute('v-if')) {
			template = parseTemplate(el, true);
		} else {
			template = document.createDocumentFragment();
			template.appendChild(el);
		}
		this.template = template;
		// linker can be cached, but only for components
		var linker;
		var cid = vm.constructor.cid;
		if(cid > 0) {
			var cacheId = cid + (isString ? el : getOuterHTML(el));
			linker = linkerCache.get(cacheId);
			if(!linker) {
				linker = compile(template, vm.$options, true);
				linkerCache.put(cacheId, linker);
			}
		} else {
			linker = compile(template, vm.$options, true);
		}
		this.linker = linker;
	}

	/**
	 * Create a fragment instance with given host and scope.
	 *
	 * @param {Vue} host
	 * @param {Object} scope
	 * @param {Fragment} parentFrag
	 */

	FragmentFactory.prototype.create = function(host, scope, parentFrag) {
		var frag = cloneNode(this.template);
		return new Fragment(this.linker, this.vm, frag, host, scope, parentFrag);
	};

	var ON = 700;
	var MODEL = 800;
	var BIND = 850;
	var TRANSITION = 1100;
	var EL = 1500;
	var COMPONENT = 1500;
	var PARTIAL = 1750;
	var IF = 2100;
	var FOR = 2200;
	var SLOT = 2300;

	var uid$3 = 0;

	var vFor = {

		priority: FOR,
		terminal: true,

		params: ['track-by', 'stagger', 'enter-stagger', 'leave-stagger'],

		bind: function bind() {
			// support "item in/of items" syntax
			var inMatch = this.expression.match(/(.*) (?:in|of) (.*)/);
			if(inMatch) {
				var itMatch = inMatch[1].match(/\((.*),(.*)\)/);
				if(itMatch) {
					this.iterator = itMatch[1].trim();
					this.alias = itMatch[2].trim();
				} else {
					this.alias = inMatch[1].trim();
				}
				this.expression = inMatch[2];
			}

			if(!this.alias) {
				'development' !== 'production' && warn('Invalid v-for expression "' + this.descriptor.raw + '": ' + 'alias is required.', this.vm);
				return;
			}

			// uid as a cache identifier
			this.id = '__v-for__' + ++uid$3;

			// check if this is an option list,
			// so that we know if we need to update the <select>'s
			// v-model when the option list has changed.
			// because v-model has a lower priority than v-for,
			// the v-model is not bound here yet, so we have to
			// retrive it in the actual updateModel() function.
			var tag = this.el.tagName;
			this.isOption = (tag === 'OPTION' || tag === 'OPTGROUP') && this.el.parentNode.tagName === 'SELECT';

			// setup anchor nodes
			this.start = createAnchor('v-for-start');
			this.end = createAnchor('v-for-end');
			replace(this.el, this.end);
			before(this.start, this.end);

			// cache
			this.cache = Object.create(null);

			// fragment factory
			this.factory = new FragmentFactory(this.vm, this.el);
		},

		update: function update(data) {
			this.diff(data);
			this.updateRef();
			this.updateModel();
		},

		/**
		 * Diff, based on new data and old data, determine the
		 * minimum amount of DOM manipulations needed to make the
		 * DOM reflect the new data Array.
		 *
		 * The algorithm diffs the new data Array by storing a
		 * hidden reference to an owner vm instance on previously
		 * seen data. This allows us to achieve O(n) which is
		 * better than a levenshtein distance based algorithm,
		 * which is O(m * n).
		 *
		 * @param {Array} data
		 */

		diff: function diff(data) {
			// check if the Array was converted from an Object
			var item = data[0];
			var convertedFromObject = this.fromObject = isObject(item) && hasOwn(item, '$key') && hasOwn(item, '$value');

			var trackByKey = this.params.trackBy;
			var oldFrags = this.frags;
			var frags = this.frags = new Array(data.length);
			var alias = this.alias;
			var iterator = this.iterator;
			var start = this.start;
			var end = this.end;
			var inDocument = inDoc(start);
			var init = !oldFrags;
			var i, l, frag, key, value, primitive;

			// First pass, go through the new Array and fill up
			// the new frags array. If a piece of data has a cached
			// instance for it, we reuse it. Otherwise build a new
			// instance.
			for(i = 0, l = data.length; i < l; i++) {
				item = data[i];
				key = convertedFromObject ? item.$key : null;
				value = convertedFromObject ? item.$value : item;
				primitive = !isObject(value);
				frag = !init && this.getCachedFrag(value, i, key);
				if(frag) {
					// reusable fragment
					frag.reused = true;
					// update $index
					frag.scope.$index = i;
					// update $key
					if(key) {
						frag.scope.$key = key;
					}
					// update iterator
					if(iterator) {
						frag.scope[iterator] = key !== null ? key : i;
					}
					// update data for track-by, object repeat &
					// primitive values.
					if(trackByKey || convertedFromObject || primitive) {
						withoutConversion(function() {
							frag.scope[alias] = value;
						});
					}
				} else {
					// new isntance
					frag = this.create(value, alias, i, key);
					frag.fresh = !init;
				}
				frags[i] = frag;
				if(init) {
					frag.before(end);
				}
			}

			// we're done for the initial render.
			if(init) {
				return;
			}

			// Second pass, go through the old fragments and
			// destroy those who are not reused (and remove them
			// from cache)
			var removalIndex = 0;
			var totalRemoved = oldFrags.length - frags.length;
			// when removing a large number of fragments, watcher removal
			// turns out to be a perf bottleneck, so we batch the watcher
			// removals into a single filter call!
			this.vm._vForRemoving = true;
			for(i = 0, l = oldFrags.length; i < l; i++) {
				frag = oldFrags[i];
				if(!frag.reused) {
					this.deleteCachedFrag(frag);
					this.remove(frag, removalIndex++, totalRemoved, inDocument);
				}
			}
			this.vm._vForRemoving = false;
			if(removalIndex) {
				this.vm._watchers = this.vm._watchers.filter(function(w) {
					return w.active;
				});
			}

			// Final pass, move/insert new fragments into the
			// right place.
			var targetPrev, prevEl, currentPrev;
			var insertionIndex = 0;
			for(i = 0, l = frags.length; i < l; i++) {
				frag = frags[i];
				// this is the frag that we should be after
				targetPrev = frags[i - 1];
				prevEl = targetPrev ? targetPrev.staggerCb ? targetPrev.staggerAnchor : targetPrev.end || targetPrev.node : start;
				if(frag.reused && !frag.staggerCb) {
					currentPrev = findPrevFrag(frag, start, this.id);
					if(currentPrev !== targetPrev && (!currentPrev ||
							// optimization for moving a single item.
							// thanks to suggestions by @livoras in #1807
							findPrevFrag(currentPrev, start, this.id) !== targetPrev)) {
						this.move(frag, prevEl);
					}
				} else {
					// new instance, or still in stagger.
					// insert with updated stagger index.
					this.insert(frag, insertionIndex++, prevEl, inDocument);
				}
				frag.reused = frag.fresh = false;
			}
		},

		/**
		 * Create a new fragment instance.
		 *
		 * @param {*} value
		 * @param {String} alias
		 * @param {Number} index
		 * @param {String} [key]
		 * @return {Fragment}
		 */

		create: function create(value, alias, index, key) {
			var host = this._host;
			// create iteration scope
			var parentScope = this._scope || this.vm;
			var scope = Object.create(parentScope);
			// ref holder for the scope
			scope.$refs = Object.create(parentScope.$refs);
			scope.$els = Object.create(parentScope.$els);
			// make sure point $parent to parent scope
			scope.$parent = parentScope;
			// for two-way binding on alias
			scope.$forContext = this;
			// define scope properties
			// important: define the scope alias without forced conversion
			// so that frozen data structures remain non-reactive.
			withoutConversion(function() {
				defineReactive(scope, alias, value);
			});
			defineReactive(scope, '$index', index);
			if(key) {
				defineReactive(scope, '$key', key);
			} else if(scope.$key) {
				// avoid accidental fallback
				def(scope, '$key', null);
			}
			if(this.iterator) {
				defineReactive(scope, this.iterator, key !== null ? key : index);
			}
			var frag = this.factory.create(host, scope, this._frag);
			frag.forId = this.id;
			this.cacheFrag(value, frag, index, key);
			return frag;
		},

		/**
		 * Update the v-ref on owner vm.
		 */

		updateRef: function updateRef() {
			var ref = this.descriptor.ref;
			if(!ref) return;
			var hash = (this._scope || this.vm).$refs;
			var refs;
			if(!this.fromObject) {
				refs = this.frags.map(findVmFromFrag);
			} else {
				refs = {};
				this.frags.forEach(function(frag) {
					refs[frag.scope.$key] = findVmFromFrag(frag);
				});
			}
			hash[ref] = refs;
		},

		/**
		 * For option lists, update the containing v-model on
		 * parent <select>.
		 */

		updateModel: function updateModel() {
			if(this.isOption) {
				var parent = this.start.parentNode;
				var model = parent && parent.__v_model;
				if(model) {
					model.forceUpdate();
				}
			}
		},

		/**
		 * Insert a fragment. Handles staggering.
		 *
		 * @param {Fragment} frag
		 * @param {Number} index
		 * @param {Node} prevEl
		 * @param {Boolean} inDocument
		 */

		insert: function insert(frag, index, prevEl, inDocument) {
			if(frag.staggerCb) {
				frag.staggerCb.cancel();
				frag.staggerCb = null;
			}
			var staggerAmount = this.getStagger(frag, index, null, 'enter');
			if(inDocument && staggerAmount) {
				// create an anchor and insert it synchronously,
				// so that we can resolve the correct order without
				// worrying about some elements not inserted yet
				var anchor = frag.staggerAnchor;
				if(!anchor) {
					anchor = frag.staggerAnchor = createAnchor('stagger-anchor');
					anchor.__v_frag = frag;
				}
				after(anchor, prevEl);
				var op = frag.staggerCb = cancellable(function() {
					frag.staggerCb = null;
					frag.before(anchor);
					remove(anchor);
				});
				setTimeout(op, staggerAmount);
			} else {
				var target = prevEl.nextSibling;
				/* istanbul ignore if */
				if(!target) {
					// reset end anchor position in case the position was messed up
					// by an external drag-n-drop library.
					after(this.end, prevEl);
					target = this.end;
				}
				frag.before(target);
			}
		},

		/**
		 * Remove a fragment. Handles staggering.
		 *
		 * @param {Fragment} frag
		 * @param {Number} index
		 * @param {Number} total
		 * @param {Boolean} inDocument
		 */

		remove: function remove(frag, index, total, inDocument) {
			if(frag.staggerCb) {
				frag.staggerCb.cancel();
				frag.staggerCb = null;
				// it's not possible for the same frag to be removed
				// twice, so if we have a pending stagger callback,
				// it means this frag is queued for enter but removed
				// before its transition started. Since it is already
				// destroyed, we can just leave it in detached state.
				return;
			}
			var staggerAmount = this.getStagger(frag, index, total, 'leave');
			if(inDocument && staggerAmount) {
				var op = frag.staggerCb = cancellable(function() {
					frag.staggerCb = null;
					frag.remove();
				});
				setTimeout(op, staggerAmount);
			} else {
				frag.remove();
			}
		},

		/**
		 * Move a fragment to a new position.
		 * Force no transition.
		 *
		 * @param {Fragment} frag
		 * @param {Node} prevEl
		 */

		move: function move(frag, prevEl) {
			// fix a common issue with Sortable:
			// if prevEl doesn't have nextSibling, this means it's
			// been dragged after the end anchor. Just re-position
			// the end anchor to the end of the container.
			/* istanbul ignore if */
			if(!prevEl.nextSibling) {
				this.end.parentNode.appendChild(this.end);
			}
			frag.before(prevEl.nextSibling, false);
		},

		/**
		 * Cache a fragment using track-by or the object key.
		 *
		 * @param {*} value
		 * @param {Fragment} frag
		 * @param {Number} index
		 * @param {String} [key]
		 */

		cacheFrag: function cacheFrag(value, frag, index, key) {
			var trackByKey = this.params.trackBy;
			var cache = this.cache;
			var primitive = !isObject(value);
			var id;
			if(key || trackByKey || primitive) {
				id = getTrackByKey(index, key, value, trackByKey);
				if(!cache[id]) {
					cache[id] = frag;
				} else if(trackByKey !== '$index') {
					'development' !== 'production' && this.warnDuplicate(value);
				}
			} else {
				id = this.id;
				if(hasOwn(value, id)) {
					if(value[id] === null) {
						value[id] = frag;
					} else {
						'development' !== 'production' && this.warnDuplicate(value);
					}
				} else if(Object.isExtensible(value)) {
					def(value, id, frag);
				} else if('development' !== 'production') {
					warn('Frozen v-for objects cannot be automatically tracked, make sure to ' + 'provide a track-by key.');
				}
			}
			frag.raw = value;
		},

		/**
		 * Get a cached fragment from the value/index/key
		 *
		 * @param {*} value
		 * @param {Number} index
		 * @param {String} key
		 * @return {Fragment}
		 */

		getCachedFrag: function getCachedFrag(value, index, key) {
			var trackByKey = this.params.trackBy;
			var primitive = !isObject(value);
			var frag;
			if(key || trackByKey || primitive) {
				var id = getTrackByKey(index, key, value, trackByKey);
				frag = this.cache[id];
			} else {
				frag = value[this.id];
			}
			if(frag && (frag.reused || frag.fresh)) {
				'development' !== 'production' && this.warnDuplicate(value);
			}
			return frag;
		},

		/**
		 * Delete a fragment from cache.
		 *
		 * @param {Fragment} frag
		 */

		deleteCachedFrag: function deleteCachedFrag(frag) {
			var value = frag.raw;
			var trackByKey = this.params.trackBy;
			var scope = frag.scope;
			var index = scope.$index;
			// fix #948: avoid accidentally fall through to
			// a parent repeater which happens to have $key.
			var key = hasOwn(scope, '$key') && scope.$key;
			var primitive = !isObject(value);
			if(trackByKey || key || primitive) {
				var id = getTrackByKey(index, key, value, trackByKey);
				this.cache[id] = null;
			} else {
				value[this.id] = null;
				frag.raw = null;
			}
		},

		/**
		 * Get the stagger amount for an insertion/removal.
		 *
		 * @param {Fragment} frag
		 * @param {Number} index
		 * @param {Number} total
		 * @param {String} type
		 */

		getStagger: function getStagger(frag, index, total, type) {
			type = type + 'Stagger';
			var trans = frag.node.__v_trans;
			var hooks = trans && trans.hooks;
			var hook = hooks && (hooks[type] || hooks.stagger);
			return hook ? hook.call(frag, index, total) : index * parseInt(this.params[type] || this.params.stagger, 10);
		},

		/**
		 * Pre-process the value before piping it through the
		 * filters. This is passed to and called by the watcher.
		 */

		_preProcess: function _preProcess(value) {
			// regardless of type, store the un-filtered raw value.
			this.rawValue = value;
			return value;
		},

		/**
		 * Post-process the value after it has been piped through
		 * the filters. This is passed to and called by the watcher.
		 *
		 * It is necessary for this to be called during the
		 * wathcer's dependency collection phase because we want
		 * the v-for to update when the source Object is mutated.
		 */

		_postProcess: function _postProcess(value) {
			if(isArray(value)) {
				return value;
			} else if(isPlainObject(value)) {
				// convert plain object to array.
				var keys = Object.keys(value);
				var i = keys.length;
				var res = new Array(i);
				var key;
				while(i--) {
					key = keys[i];
					res[i] = {
						$key: key,
						$value: value[key]
					};
				}
				return res;
			} else {
				if(typeof value === 'number' && !isNaN(value)) {
					value = range(value);
				}
				return value || [];
			}
		},

		unbind: function unbind() {
			if(this.descriptor.ref) {
				(this._scope || this.vm).$refs[this.descriptor.ref] = null;
			}
			if(this.frags) {
				var i = this.frags.length;
				var frag;
				while(i--) {
					frag = this.frags[i];
					this.deleteCachedFrag(frag);
					frag.destroy();
				}
			}
		}
	};

	/**
	 * Helper to find the previous element that is a fragment
	 * anchor. This is necessary because a destroyed frag's
	 * element could still be lingering in the DOM before its
	 * leaving transition finishes, but its inserted flag
	 * should have been set to false so we can skip them.
	 *
	 * If this is a block repeat, we want to make sure we only
	 * return frag that is bound to this v-for. (see #929)
	 *
	 * @param {Fragment} frag
	 * @param {Comment|Text} anchor
	 * @param {String} id
	 * @return {Fragment}
	 */

	function findPrevFrag(frag, anchor, id) {
		var el = frag.node.previousSibling;
		/* istanbul ignore if */
		if(!el) return;
		frag = el.__v_frag;
		while((!frag || frag.forId !== id || !frag.inserted) && el !== anchor) {
			el = el.previousSibling;
			/* istanbul ignore if */
			if(!el) return;
			frag = el.__v_frag;
		}
		return frag;
	}

	/**
	 * Find a vm from a fragment.
	 *
	 * @param {Fragment} frag
	 * @return {Vue|undefined}
	 */

	function findVmFromFrag(frag) {
		var node = frag.node;
		// handle multi-node frag
		if(frag.end) {
			while(!node.__vue__ && node !== frag.end && node.nextSibling) {
				node = node.nextSibling;
			}
		}
		return node.__vue__;
	}

	/**
	 * Create a range array from given number.
	 *
	 * @param {Number} n
	 * @return {Array}
	 */

	function range(n) {
		var i = -1;
		var ret = new Array(Math.floor(n));
		while(++i < n) {
			ret[i] = i;
		}
		return ret;
	}

	/**
	 * Get the track by key for an item.
	 *
	 * @param {Number} index
	 * @param {String} key
	 * @param {*} value
	 * @param {String} [trackByKey]
	 */

	function getTrackByKey(index, key, value, trackByKey) {
		return trackByKey ? trackByKey === '$index' ? index : trackByKey.charAt(0).match(/\w/) ? getPath(value, trackByKey) : value[trackByKey] : key || value;
	}

	if('development' !== 'production') {
		vFor.warnDuplicate = function(value) {
			warn('Duplicate value found in v-for="' + this.descriptor.raw + '": ' + JSON.stringify(value) + '. Use track-by="$index" if ' + 'you are expecting duplicate values.', this.vm);
		};
	}

	var vIf = {

		priority: IF,
		terminal: true,

		bind: function bind() {
			var el = this.el;
			if(!el.__vue__) {
				// check else block
				var next = el.nextElementSibling;
				if(next && getAttr(next, 'v-else') !== null) {
					remove(next);
					this.elseEl = next;
				}
				// check main block
				this.anchor = createAnchor('v-if');
				replace(el, this.anchor);
			} else {
				'development' !== 'production' && warn('v-if="' + this.expression + '" cannot be ' + 'used on an instance root element.', this.vm);
				this.invalid = true;
			}
		},

		update: function update(value) {
			if(this.invalid) return;
			if(value) {
				if(!this.frag) {
					this.insert();
				}
			} else {
				this.remove();
			}
		},

		insert: function insert() {
			if(this.elseFrag) {
				this.elseFrag.remove();
				this.elseFrag = null;
			}
			// lazy init factory
			if(!this.factory) {
				this.factory = new FragmentFactory(this.vm, this.el);
			}
			this.frag = this.factory.create(this._host, this._scope, this._frag);
			this.frag.before(this.anchor);
		},

		remove: function remove() {
			if(this.frag) {
				this.frag.remove();
				this.frag = null;
			}
			if(this.elseEl && !this.elseFrag) {
				if(!this.elseFactory) {
					this.elseFactory = new FragmentFactory(this.elseEl._context || this.vm, this.elseEl);
				}
				this.elseFrag = this.elseFactory.create(this._host, this._scope, this._frag);
				this.elseFrag.before(this.anchor);
			}
		},

		unbind: function unbind() {
			if(this.frag) {
				this.frag.destroy();
			}
			if(this.elseFrag) {
				this.elseFrag.destroy();
			}
		}
	};

	var show = {

		bind: function bind() {
			// check else block
			var next = this.el.nextElementSibling;
			if(next && getAttr(next, 'v-else') !== null) {
				this.elseEl = next;
			}
		},

		update: function update(value) {
			this.apply(this.el, value);
			if(this.elseEl) {
				this.apply(this.elseEl, !value);
			}
		},

		apply: function apply(el, value) {
			if(inDoc(el)) {
				applyTransition(el, value ? 1 : -1, toggle, this.vm);
			} else {
				toggle();
			}

			function toggle() {
				el.style.display = value ? '' : 'none';
			}
		}
	};

	var text$2 = {

		bind: function bind() {
			var self = this;
			var el = this.el;
			var isRange = el.type === 'range';
			var lazy = this.params.lazy;
			var number = this.params.number;
			var debounce = this.params.debounce;

			// handle composition events.
			//   http://blog.evanyou.me/2014/01/03/composition-event/
			// skip this for Android because it handles composition
			// events quite differently. Android doesn't trigger
			// composition events for language input methods e.g.
			// Chinese, but instead triggers them for spelling
			// suggestions... (see Discussion/#162)
			var composing = false;
			if(!isAndroid && !isRange) {
				this.on('compositionstart', function() {
					composing = true;
				});
				this.on('compositionend', function() {
					composing = false;
					// in IE11 the "compositionend" event fires AFTER
					// the "input" event, so the input handler is blocked
					// at the end... have to call it here.
					//
					// #1327: in lazy mode this is unecessary.
					if(!lazy) {
						self.listener();
					}
				});
			}

			// prevent messing with the input when user is typing,
			// and force update on blur.
			this.focused = false;
			if(!isRange && !lazy) {
				this.on('focus', function() {
					self.focused = true;
				});
				this.on('blur', function() {
					self.focused = false;
					// do not sync value after fragment removal (#2017)
					if(!self._frag || self._frag.inserted) {
						self.rawListener();
					}
				});
			}

			// Now attach the main listener
			this.listener = this.rawListener = function() {
				if(composing || !self._bound) {
					return;
				}
				var val = number || isRange ? toNumber(el.value) : el.value;
				self.set(val);
				// force update on next tick to avoid lock & same value
				// also only update when user is not typing
				nextTick(function() {
					if(self._bound && !self.focused) {
						self.update(self._watcher.value);
					}
				});
			};

			// apply debounce
			if(debounce) {
				this.listener = _debounce(this.listener, debounce);
			}

			// Support jQuery events, since jQuery.trigger() doesn't
			// trigger native events in some cases and some plugins
			// rely on $.trigger()
			//
			// We want to make sure if a listener is attached using
			// jQuery, it is also removed with jQuery, that's why
			// we do the check for each directive instance and
			// store that check result on itself. This also allows
			// easier test coverage control by unsetting the global
			// jQuery variable in tests.
			this.hasjQuery = typeof jQuery === 'function';
			if(this.hasjQuery) {
				var method = jQuery.fn.on ? 'on' : 'bind';
				jQuery(el)[method]('change', this.rawListener);
				if(!lazy) {
					jQuery(el)[method]('input', this.listener);
				}
			} else {
				this.on('change', this.rawListener);
				if(!lazy) {
					this.on('input', this.listener);
				}
			}

			// IE9 doesn't fire input event on backspace/del/cut
			if(!lazy && isIE9) {
				this.on('cut', function() {
					nextTick(self.listener);
				});
				this.on('keyup', function(e) {
					if(e.keyCode === 46 || e.keyCode === 8) {
						self.listener();
					}
				});
			}

			// set initial value if present
			if(el.hasAttribute('value') || el.tagName === 'TEXTAREA' && el.value.trim()) {
				this.afterBind = this.listener;
			}
		},

		update: function update(value) {
			this.el.value = _toString(value);
		},

		unbind: function unbind() {
			var el = this.el;
			if(this.hasjQuery) {
				var method = jQuery.fn.off ? 'off' : 'unbind';
				jQuery(el)[method]('change', this.listener);
				jQuery(el)[method]('input', this.listener);
			}
		}
	};

	var radio = {

		bind: function bind() {
			var self = this;
			var el = this.el;

			this.getValue = function() {
				// value overwrite via v-bind:value
				if(el.hasOwnProperty('_value')) {
					return el._value;
				}
				var val = el.value;
				if(self.params.number) {
					val = toNumber(val);
				}
				return val;
			};

			this.listener = function() {
				self.set(self.getValue());
			};
			this.on('change', this.listener);

			if(el.hasAttribute('checked')) {
				this.afterBind = this.listener;
			}
		},

		update: function update(value) {
			this.el.checked = looseEqual(value, this.getValue());
		}
	};

	var select = {

		bind: function bind() {
			var self = this;
			var el = this.el;

			// method to force update DOM using latest value.
			this.forceUpdate = function() {
				if(self._watcher) {
					self.update(self._watcher.get());
				}
			};

			// check if this is a multiple select
			var multiple = this.multiple = el.hasAttribute('multiple');

			// attach listener
			this.listener = function() {
				var value = getValue(el, multiple);
				value = self.params.number ? isArray(value) ? value.map(toNumber) : toNumber(value) : value;
				self.set(value);
			};
			this.on('change', this.listener);

			// if has initial value, set afterBind
			var initValue = getValue(el, multiple, true);
			if(multiple && initValue.length || !multiple && initValue !== null) {
				this.afterBind = this.listener;
			}

			// All major browsers except Firefox resets
			// selectedIndex with value -1 to 0 when the element
			// is appended to a new parent, therefore we have to
			// force a DOM update whenever that happens...
			this.vm.$on('hook:attached', this.forceUpdate);
		},

		update: function update(value) {
			var el = this.el;
			el.selectedIndex = -1;
			var multi = this.multiple && isArray(value);
			var options = el.options;
			var i = options.length;
			var op, val;
			while(i--) {
				op = options[i];
				val = op.hasOwnProperty('_value') ? op._value : op.value;
				/* eslint-disable eqeqeq */
				op.selected = multi ? indexOf$1(value, val) > -1 : looseEqual(value, val);
				/* eslint-enable eqeqeq */
			}
		},

		unbind: function unbind() {
			/* istanbul ignore next */
			this.vm.$off('hook:attached', this.forceUpdate);
		}
	};

	/**
	 * Get select value
	 *
	 * @param {SelectElement} el
	 * @param {Boolean} multi
	 * @param {Boolean} init
	 * @return {Array|*}
	 */

	function getValue(el, multi, init) {
		var res = multi ? [] : null;
		var op, val, selected;
		for(var i = 0, l = el.options.length; i < l; i++) {
			op = el.options[i];
			selected = init ? op.hasAttribute('selected') : op.selected;
			if(selected) {
				val = op.hasOwnProperty('_value') ? op._value : op.value;
				if(multi) {
					res.push(val);
				} else {
					return val;
				}
			}
		}
		return res;
	}

	/**
	 * Native Array.indexOf uses strict equal, but in this
	 * case we need to match string/numbers with custom equal.
	 *
	 * @param {Array} arr
	 * @param {*} val
	 */

	function indexOf$1(arr, val) {
		var i = arr.length;
		while(i--) {
			if(looseEqual(arr[i], val)) {
				return i;
			}
		}
		return -1;
	}

	var checkbox = {

		bind: function bind() {
			var self = this;
			var el = this.el;

			this.getValue = function() {
				return el.hasOwnProperty('_value') ? el._value : self.params.number ? toNumber(el.value) : el.value;
			};

			function getBooleanValue() {
				var val = el.checked;
				if(val && el.hasOwnProperty('_trueValue')) {
					return el._trueValue;
				}
				if(!val && el.hasOwnProperty('_falseValue')) {
					return el._falseValue;
				}
				return val;
			}

			this.listener = function() {
				var model = self._watcher.value;
				if(isArray(model)) {
					var val = self.getValue();
					if(el.checked) {
						if(indexOf(model, val) < 0) {
							model.push(val);
						}
					} else {
						model.$remove(val);
					}
				} else {
					self.set(getBooleanValue());
				}
			};

			this.on('change', this.listener);
			if(el.hasAttribute('checked')) {
				this.afterBind = this.listener;
			}
		},

		update: function update(value) {
			var el = this.el;
			if(isArray(value)) {
				el.checked = indexOf(value, this.getValue()) > -1;
			} else {
				if(el.hasOwnProperty('_trueValue')) {
					el.checked = looseEqual(value, el._trueValue);
				} else {
					el.checked = !!value;
				}
			}
		}
	};

	var handlers = {
		text: text$2,
		radio: radio,
		select: select,
		checkbox: checkbox
	};

	var model = {

		priority: MODEL,
		twoWay: true,
		handlers: handlers,
		params: ['lazy', 'number', 'debounce'],

		/**
		 * Possible elements:
		 *   <select>
		 *   <textarea>
		 *   <input type="*">
		 *     - text
		 *     - checkbox
		 *     - radio
		 *     - number
		 */

		bind: function bind() {
			// friendly warning...
			this.checkFilters();
			if(this.hasRead && !this.hasWrite) {
				'development' !== 'production' && warn('It seems you are using a read-only filter with ' + 'v-model="' + this.descriptor.raw + '". ' + 'You might want to use a two-way filter to ensure correct behavior.', this.vm);
			}
			var el = this.el;
			var tag = el.tagName;
			var handler;
			if(tag === 'INPUT') {
				handler = handlers[el.type] || handlers.text;
			} else if(tag === 'SELECT') {
				handler = handlers.select;
			} else if(tag === 'TEXTAREA') {
				handler = handlers.text;
			} else {
				'development' !== 'production' && warn('v-model does not support element type: ' + tag, this.vm);
				return;
			}
			el.__v_model = this;
			handler.bind.call(this);
			this.update = handler.update;
			this._unbind = handler.unbind;
		},

		/**
		 * Check read/write filter stats.
		 */

		checkFilters: function checkFilters() {
			var filters = this.filters;
			if(!filters) return;
			var i = filters.length;
			while(i--) {
				var filter = resolveAsset(this.vm.$options, 'filters', filters[i].name);
				if(typeof filter === 'function' || filter.read) {
					this.hasRead = true;
				}
				if(filter.write) {
					this.hasWrite = true;
				}
			}
		},

		unbind: function unbind() {
			this.el.__v_model = null;
			this._unbind && this._unbind();
		}
	};

	// keyCode aliases
	var keyCodes = {
		esc: 27,
		tab: 9,
		enter: 13,
		space: 32,
		'delete': [8, 46],
		up: 38,
		left: 37,
		right: 39,
		down: 40
	};

	function keyFilter(handler, keys) {
		var codes = keys.map(function(key) {
			var charCode = key.charCodeAt(0);
			if(charCode > 47 && charCode < 58) {
				return parseInt(key, 10);
			}
			if(key.length === 1) {
				charCode = key.toUpperCase().charCodeAt(0);
				if(charCode > 64 && charCode < 91) {
					return charCode;
				}
			}
			return keyCodes[key];
		});
		codes = [].concat.apply([], codes);
		return function keyHandler(e) {
			if(codes.indexOf(e.keyCode) > -1) {
				return handler.call(this, e);
			}
		};
	}

	function stopFilter(handler) {
		return function stopHandler(e) {
			e.stopPropagation();
			return handler.call(this, e);
		};
	}

	function preventFilter(handler) {
		return function preventHandler(e) {
			e.preventDefault();
			return handler.call(this, e);
		};
	}

	function selfFilter(handler) {
		return function selfHandler(e) {
			if(e.target === e.currentTarget) {
				return handler.call(this, e);
			}
		};
	}

	var on$1 = {

		priority: ON,
		acceptStatement: true,
		keyCodes: keyCodes,

		bind: function bind() {
			// deal with iframes
			if(this.el.tagName === 'IFRAME' && this.arg !== 'load') {
				var self = this;
				this.iframeBind = function() {
					on(self.el.contentWindow, self.arg, self.handler, self.modifiers.capture);
				};
				this.on('load', this.iframeBind);
			}
		},

		update: function update(handler) {
			// stub a noop for v-on with no value,
			// e.g. @mousedown.prevent
			if(!this.descriptor.raw) {
				handler = function() {};
			}

			if(typeof handler !== 'function') {
				'development' !== 'production' && warn('v-on:' + this.arg + '="' + this.expression + '" expects a function value, ' + 'got ' + handler, this.vm);
				return;
			}

			// apply modifiers
			if(this.modifiers.stop) {
				handler = stopFilter(handler);
			}
			if(this.modifiers.prevent) {
				handler = preventFilter(handler);
			}
			if(this.modifiers.self) {
				handler = selfFilter(handler);
			}
			// key filter
			var keys = Object.keys(this.modifiers).filter(function(key) {
				return key !== 'stop' && key !== 'prevent' && key !== 'self' && key !== 'capture';
			});
			if(keys.length) {
				handler = keyFilter(handler, keys);
			}

			this.reset();
			this.handler = handler;

			if(this.iframeBind) {
				this.iframeBind();
			} else {
				on(this.el, this.arg, this.handler, this.modifiers.capture);
			}
		},

		reset: function reset() {
			var el = this.iframeBind ? this.el.contentWindow : this.el;
			if(this.handler) {
				off(el, this.arg, this.handler);
			}
		},

		unbind: function unbind() {
			this.reset();
		}
	};

	var prefixes = ['-webkit-', '-moz-', '-ms-'];
	var camelPrefixes = ['Webkit', 'Moz', 'ms'];
	var importantRE = /!important;?$/;
	var propCache = Object.create(null);

	var testEl = null;

	var style = {

		deep: true,

		update: function update(value) {
			if(typeof value === 'string') {
				this.el.style.cssText = value;
			} else if(isArray(value)) {
				this.handleObject(value.reduce(extend, {}));
			} else {
				this.handleObject(value || {});
			}
		},

		handleObject: function handleObject(value) {
			// cache object styles so that only changed props
			// are actually updated.
			var cache = this.cache || (this.cache = {});
			var name, val;
			for(name in cache) {
				if(!(name in value)) {
					this.handleSingle(name, null);
					delete cache[name];
				}
			}
			for(name in value) {
				val = value[name];
				if(val !== cache[name]) {
					cache[name] = val;
					this.handleSingle(name, val);
				}
			}
		},

		handleSingle: function handleSingle(prop, value) {
			prop = normalize(prop);
			if(!prop) return; // unsupported prop
			// cast possible numbers/booleans into strings
			if(value != null) value += '';
			if(value) {
				var isImportant = importantRE.test(value) ? 'important' : '';
				if(isImportant) {
					/* istanbul ignore if */
					if('development' !== 'production') {
						warn('It\'s probably a bad idea to use !important with inline rules. ' + 'This feature will be deprecated in a future version of Vue.');
					}
					value = value.replace(importantRE, '').trim();
					this.el.style.setProperty(prop.kebab, value, isImportant);
				} else {
					this.el.style[prop.camel] = value;
				}
			} else {
				this.el.style[prop.camel] = '';
			}
		}

	};

	/**
	 * Normalize a CSS property name.
	 * - cache result
	 * - auto prefix
	 * - camelCase -> dash-case
	 *
	 * @param {String} prop
	 * @return {String}
	 */

	function normalize(prop) {
		if(propCache[prop]) {
			return propCache[prop];
		}
		var res = prefix(prop);
		propCache[prop] = propCache[res] = res;
		return res;
	}

	/**
	 * Auto detect the appropriate prefix for a CSS property.
	 * https://gist.github.com/paulirish/523692
	 *
	 * @param {String} prop
	 * @return {String}
	 */

	function prefix(prop) {
		prop = hyphenate(prop);
		var camel = camelize(prop);
		var upper = camel.charAt(0).toUpperCase() + camel.slice(1);
		if(!testEl) {
			testEl = document.createElement('div');
		}
		var i = prefixes.length;
		var prefixed;
		if(camel !== 'filter' && camel in testEl.style) {
			return {
				kebab: prop,
				camel: camel
			};
		}
		while(i--) {
			prefixed = camelPrefixes[i] + upper;
			if(prefixed in testEl.style) {
				return {
					kebab: prefixes[i] + prop,
					camel: prefixed
				};
			}
		}
	}

	// xlink
	var xlinkNS = 'http://www.w3.org/1999/xlink';
	var xlinkRE = /^xlink:/;

	// check for attributes that prohibit interpolations
	var disallowedInterpAttrRE = /^v-|^:|^@|^(?:is|transition|transition-mode|debounce|track-by|stagger|enter-stagger|leave-stagger)$/;
	// these attributes should also set their corresponding properties
	// because they only affect the initial state of the element
	var attrWithPropsRE = /^(?:value|checked|selected|muted)$/;
	// these attributes expect enumrated values of "true" or "false"
	// but are not boolean attributes
	var enumeratedAttrRE = /^(?:draggable|contenteditable|spellcheck)$/;

	// these attributes should set a hidden property for
	// binding v-model to object values
	var modelProps = {
		value: '_value',
		'true-value': '_trueValue',
		'false-value': '_falseValue'
	};

	var bind$1 = {

		priority: BIND,

		bind: function bind() {
			var attr = this.arg;
			var tag = this.el.tagName;
			// should be deep watch on object mode
			if(!attr) {
				this.deep = true;
			}
			// handle interpolation bindings
			var descriptor = this.descriptor;
			var tokens = descriptor.interp;
			if(tokens) {
				// handle interpolations with one-time tokens
				if(descriptor.hasOneTime) {
					this.expression = tokensToExp(tokens, this._scope || this.vm);
				}

				// only allow binding on native attributes
				if(disallowedInterpAttrRE.test(attr) || attr === 'name' && (tag === 'PARTIAL' || tag === 'SLOT')) {
					'development' !== 'production' && warn(attr + '="' + descriptor.raw + '": ' + 'attribute interpolation is not allowed in Vue.js ' + 'directives and special attributes.', this.vm);
					this.el.removeAttribute(attr);
					this.invalid = true;
				}

				/* istanbul ignore if */
				if('development' !== 'production') {
					var raw = attr + '="' + descriptor.raw + '": ';
					// warn src
					if(attr === 'src') {
						warn(raw + 'interpolation in "src" attribute will cause ' + 'a 404 request. Use v-bind:src instead.', this.vm);
					}

					// warn style
					if(attr === 'style') {
						warn(raw + 'interpolation in "style" attribute will cause ' + 'the attribute to be discarded in Internet Explorer. ' + 'Use v-bind:style instead.', this.vm);
					}
				}
			}
		},

		update: function update(value) {
			if(this.invalid) {
				return;
			}
			var attr = this.arg;
			if(this.arg) {
				this.handleSingle(attr, value);
			} else {
				this.handleObject(value || {});
			}
		},

		// share object handler with v-bind:class
		handleObject: style.handleObject,

		handleSingle: function handleSingle(attr, value) {
			var el = this.el;
			var interp = this.descriptor.interp;
			if(this.modifiers.camel) {
				attr = camelize(attr);
			}
			if(!interp && attrWithPropsRE.test(attr) && attr in el) {
				var attrValue = attr === 'value' ? value == null // IE9 will set input.value to "null" for null...
					?
					'' : value : value;

				if(el[attr] !== attrValue) {
					el[attr] = attrValue;
				}
			}
			// set model props
			var modelProp = modelProps[attr];
			if(!interp && modelProp) {
				el[modelProp] = value;
				// update v-model if present
				var model = el.__v_model;
				if(model) {
					model.listener();
				}
			}
			// do not set value attribute for textarea
			if(attr === 'value' && el.tagName === 'TEXTAREA') {
				el.removeAttribute(attr);
				return;
			}
			// update attribute
			if(enumeratedAttrRE.test(attr)) {
				el.setAttribute(attr, value ? 'true' : 'false');
			} else if(value != null && value !== false) {
				if(attr === 'class') {
					// handle edge case #1960:
					// class interpolation should not overwrite Vue transition class
					if(el.__v_trans) {
						value += ' ' + el.__v_trans.id + '-transition';
					}
					setClass(el, value);
				} else if(xlinkRE.test(attr)) {
					el.setAttributeNS(xlinkNS, attr, value === true ? '' : value);
				} else {
					el.setAttribute(attr, value === true ? '' : value);
				}
			} else {
				el.removeAttribute(attr);
			}
		}
	};

	var el = {

		priority: EL,

		bind: function bind() {
			/* istanbul ignore if */
			if(!this.arg) {
				return;
			}
			var id = this.id = camelize(this.arg);
			var refs = (this._scope || this.vm).$els;
			if(hasOwn(refs, id)) {
				refs[id] = this.el;
			} else {
				defineReactive(refs, id, this.el);
			}
		},

		unbind: function unbind() {
			var refs = (this._scope || this.vm).$els;
			if(refs[this.id] === this.el) {
				refs[this.id] = null;
			}
		}
	};

	var ref = {
		bind: function bind() {
			'development' !== 'production' && warn('v-ref:' + this.arg + ' must be used on a child ' + 'component. Found on <' + this.el.tagName.toLowerCase() + '>.', this.vm);
		}
	};

	var cloak = {
		bind: function bind() {
			var el = this.el;
			this.vm.$once('pre-hook:compiled', function() {
				el.removeAttribute('v-cloak');
			});
		}
	};

	// must export plain object
	var directives = {
		text: text$1,
		html: html,
		'for': vFor,
		'if': vIf,
		show: show,
		model: model,
		on: on$1,
		bind: bind$1,
		el: el,
		ref: ref,
		cloak: cloak
	};

	var vClass = {

		deep: true,

		update: function update(value) {
			if(!value) {
				this.cleanup();
			} else if(typeof value === 'string') {
				this.setClass(value.trim().split(/\s+/));
			} else {
				this.setClass(normalize$1(value));
			}
		},

		setClass: function setClass(value) {
			this.cleanup(value);
			for(var i = 0, l = value.length; i < l; i++) {
				var val = value[i];
				if(val) {
					apply(this.el, val, addClass);
				}
			}
			this.prevKeys = value;
		},

		cleanup: function cleanup(value) {
			var prevKeys = this.prevKeys;
			if(!prevKeys) return;
			var i = prevKeys.length;
			while(i--) {
				var key = prevKeys[i];
				if(!value || value.indexOf(key) < 0) {
					apply(this.el, key, removeClass);
				}
			}
		}
	};

	/**
	 * Normalize objects and arrays (potentially containing objects)
	 * into array of strings.
	 *
	 * @param {Object|Array<String|Object>} value
	 * @return {Array<String>}
	 */

	function normalize$1(value) {
		var res = [];
		if(isArray(value)) {
			for(var i = 0, l = value.length; i < l; i++) {
				var _key = value[i];
				if(_key) {
					if(typeof _key === 'string') {
						res.push(_key);
					} else {
						for(var k in _key) {
							if(_key[k]) res.push(k);
						}
					}
				}
			}
		} else if(isObject(value)) {
			for(var key in value) {
				if(value[key]) res.push(key);
			}
		}
		return res;
	}

	/**
	 * Add or remove a class/classes on an element
	 *
	 * @param {Element} el
	 * @param {String} key The class name. This may or may not
	 *                     contain a space character, in such a
	 *                     case we'll deal with multiple class
	 *                     names at once.
	 * @param {Function} fn
	 */

	function apply(el, key, fn) {
		key = key.trim();
		if(key.indexOf(' ') === -1) {
			fn(el, key);
			return;
		}
		// The key contains one or more space characters.
		// Since a class name doesn't accept such characters, we
		// treat it as multiple classes.
		var keys = key.split(/\s+/);
		for(var i = 0, l = keys.length; i < l; i++) {
			fn(el, keys[i]);
		}
	}

	var component = {

		priority: COMPONENT,

		params: ['keep-alive', 'transition-mode', 'inline-template'],

		/**
		 * Setup. Two possible usages:
		 *
		 * - static:
		 *   <comp> or <div v-component="comp">
		 *
		 * - dynamic:
		 *   <component :is="view">
		 */

		bind: function bind() {
			if(!this.el.__vue__) {
				// keep-alive cache
				this.keepAlive = this.params.keepAlive;
				if(this.keepAlive) {
					this.cache = {};
				}
				// check inline-template
				if(this.params.inlineTemplate) {
					// extract inline template as a DocumentFragment
					this.inlineTemplate = extractContent(this.el, true);
				}
				// component resolution related state
				this.pendingComponentCb = this.Component = null;
				// transition related state
				this.pendingRemovals = 0;
				this.pendingRemovalCb = null;
				// create a ref anchor
				this.anchor = createAnchor('v-component');
				replace(this.el, this.anchor);
				// remove is attribute.
				// this is removed during compilation, but because compilation is
				// cached, when the component is used elsewhere this attribute
				// will remain at link time.
				this.el.removeAttribute('is');
				this.el.removeAttribute(':is');
				// remove ref, same as above
				if(this.descriptor.ref) {
					this.el.removeAttribute('v-ref:' + hyphenate(this.descriptor.ref));
				}
				// if static, build right now.
				if(this.literal) {
					this.setComponent(this.expression);
				}
			} else {
				'development' !== 'production' && warn('cannot mount component "' + this.expression + '" ' + 'on already mounted element: ' + this.el);
			}
		},

		/**
		 * Public update, called by the watcher in the dynamic
		 * literal scenario, e.g. <component :is="view">
		 */

		update: function update(value) {
			if(!this.literal) {
				this.setComponent(value);
			}
		},

		/**
		 * Switch dynamic components. May resolve the component
		 * asynchronously, and perform transition based on
		 * specified transition mode. Accepts a few additional
		 * arguments specifically for vue-router.
		 *
		 * The callback is called when the full transition is
		 * finished.
		 *
		 * @param {String} value
		 * @param {Function} [cb]
		 */

		setComponent: function setComponent(value, cb) {
			this.invalidatePending();
			if(!value) {
				// just remove current
				this.unbuild(true);
				this.remove(this.childVM, cb);
				this.childVM = null;
			} else {
				var self = this;
				this.resolveComponent(value, function() {
					self.mountComponent(cb);
				});
			}
		},

		/**
		 * Resolve the component constructor to use when creating
		 * the child vm.
		 *
		 * @param {String|Function} value
		 * @param {Function} cb
		 */

		resolveComponent: function resolveComponent(value, cb) {
			var self = this;
			this.pendingComponentCb = cancellable(function(Component) {
				self.ComponentName = Component.options.name || (typeof value === 'string' ? value : null);
				self.Component = Component;
				cb();
			});
			this.vm._resolveComponent(value, this.pendingComponentCb);
		},

		/**
		 * Create a new instance using the current constructor and
		 * replace the existing instance. This method doesn't care
		 * whether the new component and the old one are actually
		 * the same.
		 *
		 * @param {Function} [cb]
		 */

		mountComponent: function mountComponent(cb) {
			// actual mount
			this.unbuild(true);
			var self = this;
			var activateHooks = this.Component.options.activate;
			var cached = this.getCached();
			var newComponent = this.build();
			if(activateHooks && !cached) {
				this.waitingFor = newComponent;
				callActivateHooks(activateHooks, newComponent, function() {
					if(self.waitingFor !== newComponent) {
						return;
					}
					self.waitingFor = null;
					self.transition(newComponent, cb);
				});
			} else {
				// update ref for kept-alive component
				if(cached) {
					newComponent._updateRef();
				}
				this.transition(newComponent, cb);
			}
		},

		/**
		 * When the component changes or unbinds before an async
		 * constructor is resolved, we need to invalidate its
		 * pending callback.
		 */

		invalidatePending: function invalidatePending() {
			if(this.pendingComponentCb) {
				this.pendingComponentCb.cancel();
				this.pendingComponentCb = null;
			}
		},

		/**
		 * Instantiate/insert a new child vm.
		 * If keep alive and has cached instance, insert that
		 * instance; otherwise build a new one and cache it.
		 *
		 * @param {Object} [extraOptions]
		 * @return {Vue} - the created instance
		 */

		build: function build(extraOptions) {
			var cached = this.getCached();
			if(cached) {
				return cached;
			}
			if(this.Component) {
				// default options
				var options = {
					name: this.ComponentName,
					el: cloneNode(this.el),
					template: this.inlineTemplate,
					// make sure to add the child with correct parent
					// if this is a transcluded component, its parent
					// should be the transclusion host.
					parent: this._host || this.vm,
					// if no inline-template, then the compiled
					// linker can be cached for better performance.
					_linkerCachable: !this.inlineTemplate,
					_ref: this.descriptor.ref,
					_asComponent: true,
					_isRouterView: this._isRouterView,
					// if this is a transcluded component, context
					// will be the common parent vm of this instance
					// and its host.
					_context: this.vm,
					// if this is inside an inline v-for, the scope
					// will be the intermediate scope created for this
					// repeat fragment. this is used for linking props
					// and container directives.
					_scope: this._scope,
					// pass in the owner fragment of this component.
					// this is necessary so that the fragment can keep
					// track of its contained components in order to
					// call attach/detach hooks for them.
					_frag: this._frag
				};
				// extra options
				// in 1.0.0 this is used by vue-router only
				/* istanbul ignore if */
				if(extraOptions) {
					extend(options, extraOptions);
				}
				var child = new this.Component(options);
				if(this.keepAlive) {
					this.cache[this.Component.cid] = child;
				}
				/* istanbul ignore if */
				if('development' !== 'production' && this.el.hasAttribute('transition') && child._isFragment) {
					warn('Transitions will not work on a fragment instance. ' + 'Template: ' + child.$options.template, child);
				}
				return child;
			}
		},

		/**
		 * Try to get a cached instance of the current component.
		 *
		 * @return {Vue|undefined}
		 */

		getCached: function getCached() {
			return this.keepAlive && this.cache[this.Component.cid];
		},

		/**
		 * Teardown the current child, but defers cleanup so
		 * that we can separate the destroy and removal steps.
		 *
		 * @param {Boolean} defer
		 */

		unbuild: function unbuild(defer) {
			if(this.waitingFor) {
				if(!this.keepAlive) {
					this.waitingFor.$destroy();
				}
				this.waitingFor = null;
			}
			var child = this.childVM;
			if(!child || this.keepAlive) {
				if(child) {
					// remove ref
					child._inactive = true;
					child._updateRef(true);
				}
				return;
			}
			// the sole purpose of `deferCleanup` is so that we can
			// "deactivate" the vm right now and perform DOM removal
			// later.
			child.$destroy(false, defer);
		},

		/**
		 * Remove current destroyed child and manually do
		 * the cleanup after removal.
		 *
		 * @param {Function} cb
		 */

		remove: function remove(child, cb) {
			var keepAlive = this.keepAlive;
			if(child) {
				// we may have a component switch when a previous
				// component is still being transitioned out.
				// we want to trigger only one lastest insertion cb
				// when the existing transition finishes. (#1119)
				this.pendingRemovals++;
				this.pendingRemovalCb = cb;
				var self = this;
				child.$remove(function() {
					self.pendingRemovals--;
					if(!keepAlive) child._cleanup();
					if(!self.pendingRemovals && self.pendingRemovalCb) {
						self.pendingRemovalCb();
						self.pendingRemovalCb = null;
					}
				});
			} else if(cb) {
				cb();
			}
		},

		/**
		 * Actually swap the components, depending on the
		 * transition mode. Defaults to simultaneous.
		 *
		 * @param {Vue} target
		 * @param {Function} [cb]
		 */

		transition: function transition(target, cb) {
			var self = this;
			var current = this.childVM;
			// for devtool inspection
			if(current) current._inactive = true;
			target._inactive = false;
			this.childVM = target;
			switch(self.params.transitionMode) {
				case 'in-out':
					target.$before(self.anchor, function() {
						self.remove(current, cb);
					});
					break;
				case 'out-in':
					self.remove(current, function() {
						target.$before(self.anchor, cb);
					});
					break;
				default:
					self.remove(current);
					target.$before(self.anchor, cb);
			}
		},

		/**
		 * Unbind.
		 */

		unbind: function unbind() {
			this.invalidatePending();
			// Do not defer cleanup when unbinding
			this.unbuild();
			// destroy all keep-alive cached instances
			if(this.cache) {
				for(var key in this.cache) {
					this.cache[key].$destroy();
				}
				this.cache = null;
			}
		}
	};

	/**
	 * Call activate hooks in order (asynchronous)
	 *
	 * @param {Array} hooks
	 * @param {Vue} vm
	 * @param {Function} cb
	 */

	function callActivateHooks(hooks, vm, cb) {
		var total = hooks.length;
		var called = 0;
		hooks[0].call(vm, next);

		function next() {
			if(++called >= total) {
				cb();
			} else {
				hooks[called].call(vm, next);
			}
		}
	}

	var propBindingModes = config._propBindingModes;
	var empty = {};

	// regexes
	var identRE$1 = /^[$_a-zA-Z]+[\w$]*$/;
	var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/;

	/**
	 * Compile props on a root element and return
	 * a props link function.
	 *
	 * @param {Element|DocumentFragment} el
	 * @param {Array} propOptions
	 * @param {Vue} vm
	 * @return {Function} propsLinkFn
	 */

	function compileProps(el, propOptions, vm) {
		var props = [];
		var names = Object.keys(propOptions);
		var i = names.length;
		var options, name, attr, value, path, parsed, prop;
		while(i--) {
			name = names[i];
			options = propOptions[name] || empty;

			if('development' !== 'production' && name === '$data') {
				warn('Do not use $data as prop.', vm);
				continue;
			}

			// props could contain dashes, which will be
			// interpreted as minus calculations by the parser
			// so we need to camelize the path here
			path = camelize(name);
			if(!identRE$1.test(path)) {
				'development' !== 'production' && warn('Invalid prop key: "' + name + '". Prop keys ' + 'must be valid identifiers.', vm);
				continue;
			}

			prop = {
				name: name,
				path: path,
				options: options,
				mode: propBindingModes.ONE_WAY,
				raw: null
			};

			attr = hyphenate(name);
			// first check dynamic version
			if((value = getBindAttr(el, attr)) === null) {
				if((value = getBindAttr(el, attr + '.sync')) !== null) {
					prop.mode = propBindingModes.TWO_WAY;
				} else if((value = getBindAttr(el, attr + '.once')) !== null) {
					prop.mode = propBindingModes.ONE_TIME;
				}
			}
			if(value !== null) {
				// has dynamic binding!
				prop.raw = value;
				parsed = parseDirective(value);
				value = parsed.expression;
				prop.filters = parsed.filters;
				// check binding type
				if(isLiteral(value) && !parsed.filters) {
					// for expressions containing literal numbers and
					// booleans, there's no need to setup a prop binding,
					// so we can optimize them as a one-time set.
					prop.optimizedLiteral = true;
				} else {
					prop.dynamic = true;
					// check non-settable path for two-way bindings
					if('development' !== 'production' && prop.mode === propBindingModes.TWO_WAY && !settablePathRE.test(value)) {
						prop.mode = propBindingModes.ONE_WAY;
						warn('Cannot bind two-way prop with non-settable ' + 'parent path: ' + value, vm);
					}
				}
				prop.parentPath = value;

				// warn required two-way
				if('development' !== 'production' && options.twoWay && prop.mode !== propBindingModes.TWO_WAY) {
					warn('Prop "' + name + '" expects a two-way binding type.', vm);
				}
			} else if((value = getAttr(el, attr)) !== null) {
				// has literal binding!
				prop.raw = value;
			} else if('development' !== 'production') {
				// check possible camelCase prop usage
				var lowerCaseName = path.toLowerCase();
				value = /[A-Z\-]/.test(name) && (el.getAttribute(lowerCaseName) || el.getAttribute(':' + lowerCaseName) || el.getAttribute('v-bind:' + lowerCaseName) || el.getAttribute(':' + lowerCaseName + '.once') || el.getAttribute('v-bind:' + lowerCaseName + '.once') || el.getAttribute(':' + lowerCaseName + '.sync') || el.getAttribute('v-bind:' + lowerCaseName + '.sync'));
				if(value) {
					warn('Possible usage error for prop `' + lowerCaseName + '` - ' + 'did you mean `' + attr + '`? HTML is case-insensitive, remember to use ' + 'kebab-case for props in templates.', vm);
				} else if(options.required) {
					// warn missing required
					warn('Missing required prop: ' + name, vm);
				}
			}
			// push prop
			props.push(prop);
		}
		return makePropsLinkFn(props);
	}

	/**
	 * Build a function that applies props to a vm.
	 *
	 * @param {Array} props
	 * @return {Function} propsLinkFn
	 */

	function makePropsLinkFn(props) {
		return function propsLinkFn(vm, scope) {
			// store resolved props info
			vm._props = {};
			var inlineProps = vm.$options.propsData;
			var i = props.length;
			var prop, path, options, value, raw;
			while(i--) {
				prop = props[i];
				raw = prop.raw;
				path = prop.path;
				options = prop.options;
				vm._props[path] = prop;
				if(inlineProps && hasOwn(inlineProps, path)) {
					initProp(vm, prop, inlineProps[path]);
				}
				if(raw === null) {
					// initialize absent prop
					initProp(vm, prop, undefined);
				} else if(prop.dynamic) {
					// dynamic prop
					if(prop.mode === propBindingModes.ONE_TIME) {
						// one time binding
						value = (scope || vm._context || vm).$get(prop.parentPath);
						initProp(vm, prop, value);
					} else {
						if(vm._context) {
							// dynamic binding
							vm._bindDir({
								name: 'prop',
								def: propDef,
								prop: prop
							}, null, null, scope); // el, host, scope
						} else {
							// root instance
							initProp(vm, prop, vm.$get(prop.parentPath));
						}
					}
				} else if(prop.optimizedLiteral) {
					// optimized literal, cast it and just set once
					var stripped = stripQuotes(raw);
					value = stripped === raw ? toBoolean(toNumber(raw)) : stripped;
					initProp(vm, prop, value);
				} else {
					// string literal, but we need to cater for
					// Boolean props with no value, or with same
					// literal value (e.g. disabled="disabled")
					// see https://github.com/vuejs/vue-loader/issues/182
					value = options.type === Boolean && (raw === '' || raw === hyphenate(prop.name)) ? true : raw;
					initProp(vm, prop, value);
				}
			}
		};
	}

	/**
	 * Process a prop with a rawValue, applying necessary coersions,
	 * default values & assertions and call the given callback with
	 * processed value.
	 *
	 * @param {Vue} vm
	 * @param {Object} prop
	 * @param {*} rawValue
	 * @param {Function} fn
	 */

	function processPropValue(vm, prop, rawValue, fn) {
		var isSimple = prop.dynamic && isSimplePath(prop.parentPath);
		var value = rawValue;
		if(value === undefined) {
			value = getPropDefaultValue(vm, prop);
		}
		value = coerceProp(prop, value);
		var coerced = value !== rawValue;
		if(!assertProp(prop, value, vm)) {
			value = undefined;
		}
		if(isSimple && !coerced) {
			withoutConversion(function() {
				fn(value);
			});
		} else {
			fn(value);
		}
	}

	/**
	 * Set a prop's initial value on a vm and its data object.
	 *
	 * @param {Vue} vm
	 * @param {Object} prop
	 * @param {*} value
	 */

	function initProp(vm, prop, value) {
		processPropValue(vm, prop, value, function(value) {
			defineReactive(vm, prop.path, value);
		});
	}

	/**
	 * Update a prop's value on a vm.
	 *
	 * @param {Vue} vm
	 * @param {Object} prop
	 * @param {*} value
	 */

	function updateProp(vm, prop, value) {
		processPropValue(vm, prop, value, function(value) {
			vm[prop.path] = value;
		});
	}

	/**
	 * Get the default value of a prop.
	 *
	 * @param {Vue} vm
	 * @param {Object} prop
	 * @return {*}
	 */

	function getPropDefaultValue(vm, prop) {
		// no default, return undefined
		var options = prop.options;
		if(!hasOwn(options, 'default')) {
			// absent boolean value defaults to false
			return options.type === Boolean ? false : undefined;
		}
		var def = options['default'];
		// warn against non-factory defaults for Object & Array
		if(isObject(def)) {
			'development' !== 'production' && warn('Invalid default value for prop "' + prop.name + '": ' + 'Props with type Object/Array must use a factory function ' + 'to return the default value.', vm);
		}
		// call factory function for non-Function types
		return typeof def === 'function' && options.type !== Function ? def.call(vm) : def;
	}

	/**
	 * Assert whether a prop is valid.
	 *
	 * @param {Object} prop
	 * @param {*} value
	 * @param {Vue} vm
	 */

	function assertProp(prop, value, vm) {
		if(!prop.options.required && ( // non-required
				prop.raw === null || // abscent
				value == null) // null or undefined
		) {
			return true;
		}
		var options = prop.options;
		var type = options.type;
		var valid = !type;
		var expectedTypes = [];
		if(type) {
			if(!isArray(type)) {
				type = [type];
			}
			for(var i = 0; i < type.length && !valid; i++) {
				var assertedType = assertType(value, type[i]);
				expectedTypes.push(assertedType.expectedType);
				valid = assertedType.valid;
			}
		}
		if(!valid) {
			if('development' !== 'production') {
				warn('Invalid prop: type check failed for prop "' + prop.name + '".' + ' Expected ' + expectedTypes.map(formatType).join(', ') + ', got ' + formatValue(value) + '.', vm);
			}
			return false;
		}
		var validator = options.validator;
		if(validator) {
			if(!validator(value)) {
				'development' !== 'production' && warn('Invalid prop: custom validator check failed for prop "' + prop.name + '".', vm);
				return false;
			}
		}
		return true;
	}

	/**
	 * Force parsing value with coerce option.
	 *
	 * @param {*} value
	 * @param {Object} options
	 * @return {*}
	 */

	function coerceProp(prop, value) {
		var coerce = prop.options.coerce;
		if(!coerce) {
			return value;
		}
		// coerce is a function
		return coerce(value);
	}

	/**
	 * Assert the type of a value
	 *
	 * @param {*} value
	 * @param {Function} type
	 * @return {Object}
	 */

	function assertType(value, type) {
		var valid;
		var expectedType;
		if(type === String) {
			expectedType = 'string';
			valid = typeof value === expectedType;
		} else if(type === Number) {
			expectedType = 'number';
			valid = typeof value === expectedType;
		} else if(type === Boolean) {
			expectedType = 'boolean';
			valid = typeof value === expectedType;
		} else if(type === Function) {
			expectedType = 'function';
			valid = typeof value === expectedType;
		} else if(type === Object) {
			expectedType = 'object';
			valid = isPlainObject(value);
		} else if(type === Array) {
			expectedType = 'array';
			valid = isArray(value);
		} else {
			valid = value instanceof type;
		}
		return {
			valid: valid,
			expectedType: expectedType
		};
	}

	/**
	 * Format type for output
	 *
	 * @param {String} type
	 * @return {String}
	 */

	function formatType(type) {
		return type ? type.charAt(0).toUpperCase() + type.slice(1) : 'custom type';
	}

	/**
	 * Format value
	 *
	 * @param {*} value
	 * @return {String}
	 */

	function formatValue(val) {
		return Object.prototype.toString.call(val).slice(8, -1);
	}

	var bindingModes = config._propBindingModes;

	var propDef = {

		bind: function bind() {
			var child = this.vm;
			var parent = child._context;
			// passed in from compiler directly
			var prop = this.descriptor.prop;
			var childKey = prop.path;
			var parentKey = prop.parentPath;
			var twoWay = prop.mode === bindingModes.TWO_WAY;

			var parentWatcher = this.parentWatcher = new Watcher(parent, parentKey, function(val) {
				updateProp(child, prop, val);
			}, {
				twoWay: twoWay,
				filters: prop.filters,
				// important: props need to be observed on the
				// v-for scope if present
				scope: this._scope
			});

			// set the child initial value.
			initProp(child, prop, parentWatcher.value);

			// setup two-way binding
			if(twoWay) {
				// important: defer the child watcher creation until
				// the created hook (after data observation)
				var self = this;
				child.$once('pre-hook:created', function() {
					self.childWatcher = new Watcher(child, childKey, function(val) {
						parentWatcher.set(val);
					}, {
						// ensure sync upward before parent sync down.
						// this is necessary in cases e.g. the child
						// mutates a prop array, then replaces it. (#1683)
						sync: true
					});
				});
			}
		},

		unbind: function unbind() {
			this.parentWatcher.teardown();
			if(this.childWatcher) {
				this.childWatcher.teardown();
			}
		}
	};

	var queue$1 = [];
	var queued = false;

	/**
	 * Push a job into the queue.
	 *
	 * @param {Function} job
	 */

	function pushJob(job) {
		queue$1.push(job);
		if(!queued) {
			queued = true;
			nextTick(flush);
		}
	}

	/**
	 * Flush the queue, and do one forced reflow before
	 * triggering transitions.
	 */

	function flush() {
		// Force layout
		var f = document.documentElement.offsetHeight;
		for(var i = 0; i < queue$1.length; i++) {
			queue$1[i]();
		}
		queue$1 = [];
		queued = false;
		// dummy return, so js linters don't complain about
		// unused variable f
		return f;
	}

	var TYPE_TRANSITION = 'transition';
	var TYPE_ANIMATION = 'animation';
	var transDurationProp = transitionProp + 'Duration';
	var animDurationProp = animationProp + 'Duration';

	/**
	 * If a just-entered element is applied the
	 * leave class while its enter transition hasn't started yet,
	 * and the transitioned property has the same value for both
	 * enter/leave, then the leave transition will be skipped and
	 * the transitionend event never fires. This function ensures
	 * its callback to be called after a transition has started
	 * by waiting for double raf.
	 *
	 * It falls back to setTimeout on devices that support CSS
	 * transitions but not raf (e.g. Android 4.2 browser) - since
	 * these environments are usually slow, we are giving it a
	 * relatively large timeout.
	 */

	var raf = inBrowser && window.requestAnimationFrame;
	var waitForTransitionStart = raf
		/* istanbul ignore next */
		?
		function(fn) {
			raf(function() {
				raf(fn);
			});
		} : function(fn) {
			setTimeout(fn, 50);
		};

	/**
	 * A Transition object that encapsulates the state and logic
	 * of the transition.
	 *
	 * @param {Element} el
	 * @param {String} id
	 * @param {Object} hooks
	 * @param {Vue} vm
	 */
	function Transition(el, id, hooks, vm) {
		this.id = id;
		this.el = el;
		this.enterClass = hooks && hooks.enterClass || id + '-enter';
		this.leaveClass = hooks && hooks.leaveClass || id + '-leave';
		this.hooks = hooks;
		this.vm = vm;
		// async state
		this.pendingCssEvent = this.pendingCssCb = this.cancel = this.pendingJsCb = this.op = this.cb = null;
		this.justEntered = false;
		this.entered = this.left = false;
		this.typeCache = {};
		// check css transition type
		this.type = hooks && hooks.type;
		/* istanbul ignore if */
		if('development' !== 'production') {
			if(this.type && this.type !== TYPE_TRANSITION && this.type !== TYPE_ANIMATION) {
				warn('invalid CSS transition type for transition="' + this.id + '": ' + this.type, vm);
			}
		}
		// bind
		var self = this;
		['enterNextTick', 'enterDone', 'leaveNextTick', 'leaveDone'].forEach(function(m) {
			self[m] = bind(self[m], self);
		});
	}

	var p$1 = Transition.prototype;

	/**
	 * Start an entering transition.
	 *
	 * 1. enter transition triggered
	 * 2. call beforeEnter hook
	 * 3. add enter class
	 * 4. insert/show element
	 * 5. call enter hook (with possible explicit js callback)
	 * 6. reflow
	 * 7. based on transition type:
	 *    - transition:
	 *        remove class now, wait for transitionend,
	 *        then done if there's no explicit js callback.
	 *    - animation:
	 *        wait for animationend, remove class,
	 *        then done if there's no explicit js callback.
	 *    - no css transition:
	 *        done now if there's no explicit js callback.
	 * 8. wait for either done or js callback, then call
	 *    afterEnter hook.
	 *
	 * @param {Function} op - insert/show the element
	 * @param {Function} [cb]
	 */

	p$1.enter = function(op, cb) {
		this.cancelPending();
		this.callHook('beforeEnter');
		this.cb = cb;
		addClass(this.el, this.enterClass);
		op();
		this.entered = false;
		this.callHookWithCb('enter');
		if(this.entered) {
			return; // user called done synchronously.
		}
		this.cancel = this.hooks && this.hooks.enterCancelled;
		pushJob(this.enterNextTick);
	};

	/**
	 * The "nextTick" phase of an entering transition, which is
	 * to be pushed into a queue and executed after a reflow so
	 * that removing the class can trigger a CSS transition.
	 */

	p$1.enterNextTick = function() {
		var _this = this;

		// prevent transition skipping
		this.justEntered = true;
		waitForTransitionStart(function() {
			_this.justEntered = false;
		});
		var enterDone = this.enterDone;
		var type = this.getCssTransitionType(this.enterClass);
		if(!this.pendingJsCb) {
			if(type === TYPE_TRANSITION) {
				// trigger transition by removing enter class now
				removeClass(this.el, this.enterClass);
				this.setupCssCb(transitionEndEvent, enterDone);
			} else if(type === TYPE_ANIMATION) {
				this.setupCssCb(animationEndEvent, enterDone);
			} else {
				enterDone();
			}
		} else if(type === TYPE_TRANSITION) {
			removeClass(this.el, this.enterClass);
		}
	};

	/**
	 * The "cleanup" phase of an entering transition.
	 */

	p$1.enterDone = function() {
		this.entered = true;
		this.cancel = this.pendingJsCb = null;
		removeClass(this.el, this.enterClass);
		this.callHook('afterEnter');
		if(this.cb) this.cb();
	};

	/**
	 * Start a leaving transition.
	 *
	 * 1. leave transition triggered.
	 * 2. call beforeLeave hook
	 * 3. add leave class (trigger css transition)
	 * 4. call leave hook (with possible explicit js callback)
	 * 5. reflow if no explicit js callback is provided
	 * 6. based on transition type:
	 *    - transition or animation:
	 *        wait for end event, remove class, then done if
	 *        there's no explicit js callback.
	 *    - no css transition:
	 *        done if there's no explicit js callback.
	 * 7. wait for either done or js callback, then call
	 *    afterLeave hook.
	 *
	 * @param {Function} op - remove/hide the element
	 * @param {Function} [cb]
	 */

	p$1.leave = function(op, cb) {
		this.cancelPending();
		this.callHook('beforeLeave');
		this.op = op;
		this.cb = cb;
		addClass(this.el, this.leaveClass);
		this.left = false;
		this.callHookWithCb('leave');
		if(this.left) {
			return; // user called done synchronously.
		}
		this.cancel = this.hooks && this.hooks.leaveCancelled;
		// only need to handle leaveDone if
		// 1. the transition is already done (synchronously called
		//    by the user, which causes this.op set to null)
		// 2. there's no explicit js callback
		if(this.op && !this.pendingJsCb) {
			// if a CSS transition leaves immediately after enter,
			// the transitionend event never fires. therefore we
			// detect such cases and end the leave immediately.
			if(this.justEntered) {
				this.leaveDone();
			} else {
				pushJob(this.leaveNextTick);
			}
		}
	};

	/**
	 * The "nextTick" phase of a leaving transition.
	 */

	p$1.leaveNextTick = function() {
		var type = this.getCssTransitionType(this.leaveClass);
		if(type) {
			var event = type === TYPE_TRANSITION ? transitionEndEvent : animationEndEvent;
			this.setupCssCb(event, this.leaveDone);
		} else {
			this.leaveDone();
		}
	};

	/**
	 * The "cleanup" phase of a leaving transition.
	 */

	p$1.leaveDone = function() {
		this.left = true;
		this.cancel = this.pendingJsCb = null;
		this.op();
		removeClass(this.el, this.leaveClass);
		this.callHook('afterLeave');
		if(this.cb) this.cb();
		this.op = null;
	};

	/**
	 * Cancel any pending callbacks from a previously running
	 * but not finished transition.
	 */

	p$1.cancelPending = function() {
		this.op = this.cb = null;
		var hasPending = false;
		if(this.pendingCssCb) {
			hasPending = true;
			off(this.el, this.pendingCssEvent, this.pendingCssCb);
			this.pendingCssEvent = this.pendingCssCb = null;
		}
		if(this.pendingJsCb) {
			hasPending = true;
			this.pendingJsCb.cancel();
			this.pendingJsCb = null;
		}
		if(hasPending) {
			removeClass(this.el, this.enterClass);
			removeClass(this.el, this.leaveClass);
		}
		if(this.cancel) {
			this.cancel.call(this.vm, this.el);
			this.cancel = null;
		}
	};

	/**
	 * Call a user-provided synchronous hook function.
	 *
	 * @param {String} type
	 */

	p$1.callHook = function(type) {
		if(this.hooks && this.hooks[type]) {
			this.hooks[type].call(this.vm, this.el);
		}
	};

	/**
	 * Call a user-provided, potentially-async hook function.
	 * We check for the length of arguments to see if the hook
	 * expects a `done` callback. If true, the transition's end
	 * will be determined by when the user calls that callback;
	 * otherwise, the end is determined by the CSS transition or
	 * animation.
	 *
	 * @param {String} type
	 */

	p$1.callHookWithCb = function(type) {
		var hook = this.hooks && this.hooks[type];
		if(hook) {
			if(hook.length > 1) {
				this.pendingJsCb = cancellable(this[type + 'Done']);
			}
			hook.call(this.vm, this.el, this.pendingJsCb);
		}
	};

	/**
	 * Get an element's transition type based on the
	 * calculated styles.
	 *
	 * @param {String} className
	 * @return {Number}
	 */

	p$1.getCssTransitionType = function(className) {
		/* istanbul ignore if */
		if(!transitionEndEvent ||
			// skip CSS transitions if page is not visible -
			// this solves the issue of transitionend events not
			// firing until the page is visible again.
			// pageVisibility API is supported in IE10+, same as
			// CSS transitions.
			document.hidden ||
			// explicit js-only transition
			this.hooks && this.hooks.css === false ||
			// element is hidden
			isHidden(this.el)) {
			return;
		}
		var type = this.type || this.typeCache[className];
		if(type) return type;
		var inlineStyles = this.el.style;
		var computedStyles = window.getComputedStyle(this.el);
		var transDuration = inlineStyles[transDurationProp] || computedStyles[transDurationProp];
		if(transDuration && transDuration !== '0s') {
			type = TYPE_TRANSITION;
		} else {
			var animDuration = inlineStyles[animDurationProp] || computedStyles[animDurationProp];
			if(animDuration && animDuration !== '0s') {
				type = TYPE_ANIMATION;
			}
		}
		if(type) {
			this.typeCache[className] = type;
		}
		return type;
	};

	/**
	 * Setup a CSS transitionend/animationend callback.
	 *
	 * @param {String} event
	 * @param {Function} cb
	 */

	p$1.setupCssCb = function(event, cb) {
		this.pendingCssEvent = event;
		var self = this;
		var el = this.el;
		var onEnd = this.pendingCssCb = function(e) {
			if(e.target === el) {
				off(el, event, onEnd);
				self.pendingCssEvent = self.pendingCssCb = null;
				if(!self.pendingJsCb && cb) {
					cb();
				}
			}
		};
		on(el, event, onEnd);
	};

	/**
	 * Check if an element is hidden - in that case we can just
	 * skip the transition alltogether.
	 *
	 * @param {Element} el
	 * @return {Boolean}
	 */

	function isHidden(el) {
		if(/svg$/.test(el.namespaceURI)) {
			// SVG elements do not have offset(Width|Height)
			// so we need to check the client rect
			var rect = el.getBoundingClientRect();
			return !(rect.width || rect.height);
		} else {
			return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length);
		}
	}

	var transition$1 = {

		priority: TRANSITION,

		update: function update(id, oldId) {
			var el = this.el;
			// resolve on owner vm
			var hooks = resolveAsset(this.vm.$options, 'transitions', id);
			id = id || 'v';
			el.__v_trans = new Transition(el, id, hooks, this.vm);
			if(oldId) {
				removeClass(el, oldId + '-transition');
			}
			addClass(el, id + '-transition');
		}
	};

	var internalDirectives = {
		style: style,
		'class': vClass,
		component: component,
		prop: propDef,
		transition: transition$1
	};

	// special binding prefixes
	var bindRE = /^v-bind:|^:/;
	var onRE = /^v-on:|^@/;
	var dirAttrRE = /^v-([^:]+)(?:$|:(.*)$)/;
	var modifierRE = /\.[^\.]+/g;
	var transitionRE = /^(v-bind:|:)?transition$/;

	// default directive priority
	var DEFAULT_PRIORITY = 1000;
	var DEFAULT_TERMINAL_PRIORITY = 2000;

	/**
	 * Compile a template and return a reusable composite link
	 * function, which recursively contains more link functions
	 * inside. This top level compile function would normally
	 * be called on instance root nodes, but can also be used
	 * for partial compilation if the partial argument is true.
	 *
	 * The returned composite link function, when called, will
	 * return an unlink function that tearsdown all directives
	 * created during the linking phase.
	 *
	 * @param {Element|DocumentFragment} el
	 * @param {Object} options
	 * @param {Boolean} partial
	 * @return {Function}
	 */

	function compile(el, options, partial) {
		// link function for the node itself.
		var nodeLinkFn = partial || !options._asComponent ? compileNode(el, options) : null;
		// link function for the childNodes
		var childLinkFn = !(nodeLinkFn && nodeLinkFn.terminal) && !isScript(el) && el.hasChildNodes() ? compileNodeList(el.childNodes, options) : null;

		/**
		 * A composite linker function to be called on a already
		 * compiled piece of DOM, which instantiates all directive
		 * instances.
		 *
		 * @param {Vue} vm
		 * @param {Element|DocumentFragment} el
		 * @param {Vue} [host] - host vm of transcluded content
		 * @param {Object} [scope] - v-for scope
		 * @param {Fragment} [frag] - link context fragment
		 * @return {Function|undefined}
		 */

		return function compositeLinkFn(vm, el, host, scope, frag) {
			// cache childNodes before linking parent, fix #657
			var childNodes = toArray(el.childNodes);
			// link
			var dirs = linkAndCapture(function compositeLinkCapturer() {
				if(nodeLinkFn) nodeLinkFn(vm, el, host, scope, frag);
				if(childLinkFn) childLinkFn(vm, childNodes, host, scope, frag);
			}, vm);
			return makeUnlinkFn(vm, dirs);
		};
	}

	/**
	 * Apply a linker to a vm/element pair and capture the
	 * directives created during the process.
	 *
	 * @param {Function} linker
	 * @param {Vue} vm
	 */

	function linkAndCapture(linker, vm) {
		/* istanbul ignore if */
		if('development' === 'production') {}
		var originalDirCount = vm._directives.length;
		linker();
		var dirs = vm._directives.slice(originalDirCount);
		dirs.sort(directiveComparator);
		for(var i = 0, l = dirs.length; i < l; i++) {
			dirs[i]._bind();
		}
		return dirs;
	}

	/**
	 * Directive priority sort comparator
	 *
	 * @param {Object} a
	 * @param {Object} b
	 */

	function directiveComparator(a, b) {
		a = a.descriptor.def.priority || DEFAULT_PRIORITY;
		b = b.descriptor.def.priority || DEFAULT_PRIORITY;
		return a > b ? -1 : a === b ? 0 : 1;
	}

	/**
	 * Linker functions return an unlink function that
	 * tearsdown all directives instances generated during
	 * the process.
	 *
	 * We create unlink functions with only the necessary
	 * information to avoid retaining additional closures.
	 *
	 * @param {Vue} vm
	 * @param {Array} dirs
	 * @param {Vue} [context]
	 * @param {Array} [contextDirs]
	 * @return {Function}
	 */

	function makeUnlinkFn(vm, dirs, context, contextDirs) {
		function unlink(destroying) {
			teardownDirs(vm, dirs, destroying);
			if(context && contextDirs) {
				teardownDirs(context, contextDirs);
			}
		}
		// expose linked directives
		unlink.dirs = dirs;
		return unlink;
	}

	/**
	 * Teardown partial linked directives.
	 *
	 * @param {Vue} vm
	 * @param {Array} dirs
	 * @param {Boolean} destroying
	 */

	function teardownDirs(vm, dirs, destroying) {
		var i = dirs.length;
		while(i--) {
			dirs[i]._teardown();
			if('development' !== 'production' && !destroying) {
				vm._directives.$remove(dirs[i]);
			}
		}
	}

	/**
	 * Compile link props on an instance.
	 *
	 * @param {Vue} vm
	 * @param {Element} el
	 * @param {Object} props
	 * @param {Object} [scope]
	 * @return {Function}
	 */

	function compileAndLinkProps(vm, el, props, scope) {
		var propsLinkFn = compileProps(el, props, vm);
		var propDirs = linkAndCapture(function() {
			propsLinkFn(vm, scope);
		}, vm);
		return makeUnlinkFn(vm, propDirs);
	}

	/**
	 * Compile the root element of an instance.
	 *
	 * 1. attrs on context container (context scope)
	 * 2. attrs on the component template root node, if
	 *    replace:true (child scope)
	 *
	 * If this is a fragment instance, we only need to compile 1.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @param {Object} contextOptions
	 * @return {Function}
	 */

	function compileRoot(el, options, contextOptions) {
		var containerAttrs = options._containerAttrs;
		var replacerAttrs = options._replacerAttrs;
		var contextLinkFn, replacerLinkFn;

		// only need to compile other attributes for
		// non-fragment instances
		if(el.nodeType !== 11) {
			// for components, container and replacer need to be
			// compiled separately and linked in different scopes.
			if(options._asComponent) {
				// 2. container attributes
				if(containerAttrs && contextOptions) {
					contextLinkFn = compileDirectives(containerAttrs, contextOptions);
				}
				if(replacerAttrs) {
					// 3. replacer attributes
					replacerLinkFn = compileDirectives(replacerAttrs, options);
				}
			} else {
				// non-component, just compile as a normal element.
				replacerLinkFn = compileDirectives(el.attributes, options);
			}
		} else if('development' !== 'production' && containerAttrs) {
			// warn container directives for fragment instances
			var names = containerAttrs.filter(function(attr) {
				// allow vue-loader/vueify scoped css attributes
				return attr.name.indexOf('_v-') < 0 &&
					// allow event listeners
					!onRE.test(attr.name) &&
					// allow slots
					attr.name !== 'slot';
			}).map(function(attr) {
				return '"' + attr.name + '"';
			});
			if(names.length) {
				var plural = names.length > 1;
				warn('Attribute' + (plural ? 's ' : ' ') + names.join(', ') + (plural ? ' are' : ' is') + ' ignored on component ' + '<' + options.el.tagName.toLowerCase() + '> because ' + 'the component is a fragment instance: ' + 'http://vuejs.org/guide/components.html#Fragment-Instance');
			}
		}

		options._containerAttrs = options._replacerAttrs = null;
		return function rootLinkFn(vm, el, scope) {
			// link context scope dirs
			var context = vm._context;
			var contextDirs;
			if(context && contextLinkFn) {
				contextDirs = linkAndCapture(function() {
					contextLinkFn(context, el, null, scope);
				}, context);
			}

			// link self
			var selfDirs = linkAndCapture(function() {
				if(replacerLinkFn) replacerLinkFn(vm, el);
			}, vm);

			// return the unlink function that tearsdown context
			// container directives.
			return makeUnlinkFn(vm, selfDirs, context, contextDirs);
		};
	}

	/**
	 * Compile a node and return a nodeLinkFn based on the
	 * node type.
	 *
	 * @param {Node} node
	 * @param {Object} options
	 * @return {Function|null}
	 */

	function compileNode(node, options) {
		var type = node.nodeType;
		if(type === 1 && !isScript(node)) {
			return compileElement(node, options);
		} else if(type === 3 && node.data.trim()) {
			return compileTextNode(node, options);
		} else {
			return null;
		}
	}

	/**
	 * Compile an element and return a nodeLinkFn.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Function|null}
	 */

	function compileElement(el, options) {
		// preprocess textareas.
		// textarea treats its text content as the initial value.
		// just bind it as an attr directive for value.
		if(el.tagName === 'TEXTAREA') {
			var tokens = parseText(el.value);
			if(tokens) {
				el.setAttribute(':value', tokensToExp(tokens));
				el.value = '';
			}
		}
		var linkFn;
		var hasAttrs = el.hasAttributes();
		var attrs = hasAttrs && toArray(el.attributes);
		// check terminal directives (for & if)
		if(hasAttrs) {
			linkFn = checkTerminalDirectives(el, attrs, options);
		}
		// check element directives
		if(!linkFn) {
			linkFn = checkElementDirectives(el, options);
		}
		// check component
		if(!linkFn) {
			linkFn = checkComponent(el, options);
		}
		// normal directives
		if(!linkFn && hasAttrs) {
			linkFn = compileDirectives(attrs, options);
		}
		return linkFn;
	}

	/**
	 * Compile a textNode and return a nodeLinkFn.
	 *
	 * @param {TextNode} node
	 * @param {Object} options
	 * @return {Function|null} textNodeLinkFn
	 */

	function compileTextNode(node, options) {
		// skip marked text nodes
		if(node._skip) {
			return removeText;
		}

		var tokens = parseText(node.wholeText);
		if(!tokens) {
			return null;
		}

		// mark adjacent text nodes as skipped,
		// because we are using node.wholeText to compile
		// all adjacent text nodes together. This fixes
		// issues in IE where sometimes it splits up a single
		// text node into multiple ones.
		var next = node.nextSibling;
		while(next && next.nodeType === 3) {
			next._skip = true;
			next = next.nextSibling;
		}

		var frag = document.createDocumentFragment();
		var el, token;
		for(var i = 0, l = tokens.length; i < l; i++) {
			token = tokens[i];
			el = token.tag ? processTextToken(token, options) : document.createTextNode(token.value);
			frag.appendChild(el);
		}
		return makeTextNodeLinkFn(tokens, frag, options);
	}

	/**
	 * Linker for an skipped text node.
	 *
	 * @param {Vue} vm
	 * @param {Text} node
	 */

	function removeText(vm, node) {
		remove(node);
	}

	/**
	 * Process a single text token.
	 *
	 * @param {Object} token
	 * @param {Object} options
	 * @return {Node}
	 */

	function processTextToken(token, options) {
		var el;
		if(token.oneTime) {
			el = document.createTextNode(token.value);
		} else {
			if(token.html) {
				el = document.createComment('v-html');
				setTokenType('html');
			} else {
				// IE will clean up empty textNodes during
				// frag.cloneNode(true), so we have to give it
				// something here...
				el = document.createTextNode(' ');
				setTokenType('text');
			}
		}

		function setTokenType(type) {
			if(token.descriptor) return;
			var parsed = parseDirective(token.value);
			token.descriptor = {
				name: type,
				def: directives[type],
				expression: parsed.expression,
				filters: parsed.filters
			};
		}
		return el;
	}

	/**
	 * Build a function that processes a textNode.
	 *
	 * @param {Array<Object>} tokens
	 * @param {DocumentFragment} frag
	 */

	function makeTextNodeLinkFn(tokens, frag) {
		return function textNodeLinkFn(vm, el, host, scope) {
			var fragClone = frag.cloneNode(true);
			var childNodes = toArray(fragClone.childNodes);
			var token, value, node;
			for(var i = 0, l = tokens.length; i < l; i++) {
				token = tokens[i];
				value = token.value;
				if(token.tag) {
					node = childNodes[i];
					if(token.oneTime) {
						value = (scope || vm).$eval(value);
						if(token.html) {
							replace(node, parseTemplate(value, true));
						} else {
							node.data = value;
						}
					} else {
						vm._bindDir(token.descriptor, node, host, scope);
					}
				}
			}
			replace(el, fragClone);
		};
	}

	/**
	 * Compile a node list and return a childLinkFn.
	 *
	 * @param {NodeList} nodeList
	 * @param {Object} options
	 * @return {Function|undefined}
	 */

	function compileNodeList(nodeList, options) {
		var linkFns = [];
		var nodeLinkFn, childLinkFn, node;
		for(var i = 0, l = nodeList.length; i < l; i++) {
			node = nodeList[i];
			nodeLinkFn = compileNode(node, options);
			childLinkFn = !(nodeLinkFn && nodeLinkFn.terminal) && node.tagName !== 'SCRIPT' && node.hasChildNodes() ? compileNodeList(node.childNodes, options) : null;
			linkFns.push(nodeLinkFn, childLinkFn);
		}
		return linkFns.length ? makeChildLinkFn(linkFns) : null;
	}

	/**
	 * Make a child link function for a node's childNodes.
	 *
	 * @param {Array<Function>} linkFns
	 * @return {Function} childLinkFn
	 */

	function makeChildLinkFn(linkFns) {
		return function childLinkFn(vm, nodes, host, scope, frag) {
			var node, nodeLinkFn, childrenLinkFn;
			for(var i = 0, n = 0, l = linkFns.length; i < l; n++) {
				node = nodes[n];
				nodeLinkFn = linkFns[i++];
				childrenLinkFn = linkFns[i++];
				// cache childNodes before linking parent, fix #657
				var childNodes = toArray(node.childNodes);
				if(nodeLinkFn) {
					nodeLinkFn(vm, node, host, scope, frag);
				}
				if(childrenLinkFn) {
					childrenLinkFn(vm, childNodes, host, scope, frag);
				}
			}
		};
	}

	/**
	 * Check for element directives (custom elements that should
	 * be resovled as terminal directives).
	 *
	 * @param {Element} el
	 * @param {Object} options
	 */

	function checkElementDirectives(el, options) {
		var tag = el.tagName.toLowerCase();
		if(commonTagRE.test(tag)) {
			return;
		}
		var def = resolveAsset(options, 'elementDirectives', tag);
		if(def) {
			return makeTerminalNodeLinkFn(el, tag, '', options, def);
		}
	}

	/**
	 * Check if an element is a component. If yes, return
	 * a component link function.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Function|undefined}
	 */

	function checkComponent(el, options) {
		var component = checkComponentAttr(el, options);
		if(component) {
			var ref = findRef(el);
			var descriptor = {
				name: 'component',
				ref: ref,
				expression: component.id,
				def: internalDirectives.component,
				modifiers: {
					literal: !component.dynamic
				}
			};
			var componentLinkFn = function componentLinkFn(vm, el, host, scope, frag) {
				if(ref) {
					defineReactive((scope || vm).$refs, ref, null);
				}
				vm._bindDir(descriptor, el, host, scope, frag);
			};
			componentLinkFn.terminal = true;
			return componentLinkFn;
		}
	}

	/**
	 * Check an element for terminal directives in fixed order.
	 * If it finds one, return a terminal link function.
	 *
	 * @param {Element} el
	 * @param {Array} attrs
	 * @param {Object} options
	 * @return {Function} terminalLinkFn
	 */

	function checkTerminalDirectives(el, attrs, options) {
		// skip v-pre
		if(getAttr(el, 'v-pre') !== null) {
			return skip;
		}
		// skip v-else block, but only if following v-if
		if(el.hasAttribute('v-else')) {
			var prev = el.previousElementSibling;
			if(prev && prev.hasAttribute('v-if')) {
				return skip;
			}
		}

		var attr, name, value, modifiers, matched, dirName, rawName, arg, def, termDef;
		for(var i = 0, j = attrs.length; i < j; i++) {
			attr = attrs[i];
			name = attr.name.replace(modifierRE, '');
			if(matched = name.match(dirAttrRE)) {
				def = resolveAsset(options, 'directives', matched[1]);
				if(def && def.terminal) {
					if(!termDef || (def.priority || DEFAULT_TERMINAL_PRIORITY) > termDef.priority) {
						termDef = def;
						rawName = attr.name;
						modifiers = parseModifiers(attr.name);
						value = attr.value;
						dirName = matched[1];
						arg = matched[2];
					}
				}
			}
		}

		if(termDef) {
			return makeTerminalNodeLinkFn(el, dirName, value, options, termDef, rawName, arg, modifiers);
		}
	}

	function skip() {}
	skip.terminal = true;

	/**
	 * Build a node link function for a terminal directive.
	 * A terminal link function terminates the current
	 * compilation recursion and handles compilation of the
	 * subtree in the directive.
	 *
	 * @param {Element} el
	 * @param {String} dirName
	 * @param {String} value
	 * @param {Object} options
	 * @param {Object} def
	 * @param {String} [rawName]
	 * @param {String} [arg]
	 * @param {Object} [modifiers]
	 * @return {Function} terminalLinkFn
	 */

	function makeTerminalNodeLinkFn(el, dirName, value, options, def, rawName, arg, modifiers) {
		var parsed = parseDirective(value);
		var descriptor = {
			name: dirName,
			arg: arg,
			expression: parsed.expression,
			filters: parsed.filters,
			raw: value,
			attr: rawName,
			modifiers: modifiers,
			def: def
		};
		// check ref for v-for and router-view
		if(dirName === 'for' || dirName === 'router-view') {
			descriptor.ref = findRef(el);
		}
		var fn = function terminalNodeLinkFn(vm, el, host, scope, frag) {
			if(descriptor.ref) {
				defineReactive((scope || vm).$refs, descriptor.ref, null);
			}
			vm._bindDir(descriptor, el, host, scope, frag);
		};
		fn.terminal = true;
		return fn;
	}

	/**
	 * Compile the directives on an element and return a linker.
	 *
	 * @param {Array|NamedNodeMap} attrs
	 * @param {Object} options
	 * @return {Function}
	 */

	function compileDirectives(attrs, options) {
		var i = attrs.length;
		var dirs = [];
		var attr, name, value, rawName, rawValue, dirName, arg, modifiers, dirDef, tokens, matched;
		while(i--) {
			attr = attrs[i];
			name = rawName = attr.name;
			value = rawValue = attr.value;
			tokens = parseText(value);
			// reset arg
			arg = null;
			// check modifiers
			modifiers = parseModifiers(name);
			name = name.replace(modifierRE, '');

			// attribute interpolations
			if(tokens) {
				value = tokensToExp(tokens);
				arg = name;
				pushDir('bind', directives.bind, tokens);
				// warn against mixing mustaches with v-bind
				if('development' !== 'production') {
					if(name === 'class' && Array.prototype.some.call(attrs, function(attr) {
							return attr.name === ':class' || attr.name === 'v-bind:class';
						})) {
						warn('class="' + rawValue + '": Do not mix mustache interpolation ' + 'and v-bind for "class" on the same element. Use one or the other.', options);
					}
				}
			} else

				// special attribute: transition
				if(transitionRE.test(name)) {
					modifiers.literal = !bindRE.test(name);
					pushDir('transition', internalDirectives.transition);
				} else

					// event handlers
					if(onRE.test(name)) {
						arg = name.replace(onRE, '');
						pushDir('on', directives.on);
					} else

						// attribute bindings
						if(bindRE.test(name)) {
							dirName = name.replace(bindRE, '');
							if(dirName === 'style' || dirName === 'class') {
								pushDir(dirName, internalDirectives[dirName]);
							} else {
								arg = dirName;
								pushDir('bind', directives.bind);
							}
						} else

							// normal directives
							if(matched = name.match(dirAttrRE)) {
								dirName = matched[1];
								arg = matched[2];

								// skip v-else (when used with v-show)
								if(dirName === 'else') {
									continue;
								}

								dirDef = resolveAsset(options, 'directives', dirName, true);
								if(dirDef) {
									pushDir(dirName, dirDef);
								}
							}
		}

		/**
		 * Push a directive.
		 *
		 * @param {String} dirName
		 * @param {Object|Function} def
		 * @param {Array} [interpTokens]
		 */

		function pushDir(dirName, def, interpTokens) {
			var hasOneTimeToken = interpTokens && hasOneTime(interpTokens);
			var parsed = !hasOneTimeToken && parseDirective(value);
			dirs.push({
				name: dirName,
				attr: rawName,
				raw: rawValue,
				def: def,
				arg: arg,
				modifiers: modifiers,
				// conversion from interpolation strings with one-time token
				// to expression is differed until directive bind time so that we
				// have access to the actual vm context for one-time bindings.
				expression: parsed && parsed.expression,
				filters: parsed && parsed.filters,
				interp: interpTokens,
				hasOneTime: hasOneTimeToken
			});
		}

		if(dirs.length) {
			return makeNodeLinkFn(dirs);
		}
	}

	/**
	 * Parse modifiers from directive attribute name.
	 *
	 * @param {String} name
	 * @return {Object}
	 */

	function parseModifiers(name) {
		var res = Object.create(null);
		var match = name.match(modifierRE);
		if(match) {
			var i = match.length;
			while(i--) {
				res[match[i].slice(1)] = true;
			}
		}
		return res;
	}

	/**
	 * Build a link function for all directives on a single node.
	 *
	 * @param {Array} directives
	 * @return {Function} directivesLinkFn
	 */

	function makeNodeLinkFn(directives) {
		return function nodeLinkFn(vm, el, host, scope, frag) {
			// reverse apply because it's sorted low to high
			var i = directives.length;
			while(i--) {
				vm._bindDir(directives[i], el, host, scope, frag);
			}
		};
	}

	/**
	 * Check if an interpolation string contains one-time tokens.
	 *
	 * @param {Array} tokens
	 * @return {Boolean}
	 */

	function hasOneTime(tokens) {
		var i = tokens.length;
		while(i--) {
			if(tokens[i].oneTime) return true;
		}
	}

	function isScript(el) {
		return el.tagName === 'SCRIPT' && (!el.hasAttribute('type') || el.getAttribute('type') === 'text/javascript');
	}

	var specialCharRE = /[^\w\-:\.]/;

	/**
	 * Process an element or a DocumentFragment based on a
	 * instance option object. This allows us to transclude
	 * a template node/fragment before the instance is created,
	 * so the processed fragment can then be cloned and reused
	 * in v-for.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Element|DocumentFragment}
	 */

	function transclude(el, options) {
		// extract container attributes to pass them down
		// to compiler, because they need to be compiled in
		// parent scope. we are mutating the options object here
		// assuming the same object will be used for compile
		// right after this.
		if(options) {
			options._containerAttrs = extractAttrs(el);
		}
		// for template tags, what we want is its content as
		// a documentFragment (for fragment instances)
		if(isTemplate(el)) {
			el = parseTemplate(el);
		}
		if(options) {
			if(options._asComponent && !options.template) {
				options.template = '<slot></slot>';
			}
			if(options.template) {
				options._content = extractContent(el);
				el = transcludeTemplate(el, options);
			}
		}
		if(isFragment(el)) {
			// anchors for fragment instance
			// passing in `persist: true` to avoid them being
			// discarded by IE during template cloning
			prepend(createAnchor('v-start', true), el);
			el.appendChild(createAnchor('v-end', true));
		}
		return el;
	}

	/**
	 * Process the template option.
	 * If the replace option is true this will swap the $el.
	 *
	 * @param {Element} el
	 * @param {Object} options
	 * @return {Element|DocumentFragment}
	 */

	function transcludeTemplate(el, options) {
		var template = options.template;
		var frag = parseTemplate(template, true);
		if(frag) {
			var replacer = frag.firstChild;
			var tag = replacer.tagName && replacer.tagName.toLowerCase();
			if(options.replace) {
				/* istanbul ignore if */
				if(el === document.body) {
					'development' !== 'production' && warn('You are mounting an instance with a template to ' + '<body>. This will replace <body> entirely. You ' + 'should probably use `replace: false` here.');
				}
				// there are many cases where the instance must
				// become a fragment instance: basically anything that
				// can create more than 1 root nodes.
				if(
					// multi-children template
					frag.childNodes.length > 1 ||
					// non-element template
					replacer.nodeType !== 1 ||
					// single nested component
					tag === 'component' || resolveAsset(options, 'components', tag) || hasBindAttr(replacer, 'is') ||
					// element directive
					resolveAsset(options, 'elementDirectives', tag) ||
					// for block
					replacer.hasAttribute('v-for') ||
					// if block
					replacer.hasAttribute('v-if')) {
					return frag;
				} else {
					options._replacerAttrs = extractAttrs(replacer);
					mergeAttrs(el, replacer);
					return replacer;
				}
			} else {
				el.appendChild(frag);
				return el;
			}
		} else {
			'development' !== 'production' && warn('Invalid template option: ' + template);
		}
	}

	/**
	 * Helper to extract a component container's attributes
	 * into a plain object array.
	 *
	 * @param {Element} el
	 * @return {Array}
	 */

	function extractAttrs(el) {
		if(el.nodeType === 1 && el.hasAttributes()) {
			return toArray(el.attributes);
		}
	}

	/**
	 * Merge the attributes of two elements, and make sure
	 * the class names are merged properly.
	 *
	 * @param {Element} from
	 * @param {Element} to
	 */

	function mergeAttrs(from, to) {
		var attrs = from.attributes;
		var i = attrs.length;
		var name, value;
		while(i--) {
			name = attrs[i].name;
			value = attrs[i].value;
			if(!to.hasAttribute(name) && !specialCharRE.test(name)) {
				to.setAttribute(name, value);
			} else if(name === 'class' && !parseText(value) && (value = value.trim())) {
				value.split(/\s+/).forEach(function(cls) {
					addClass(to, cls);
				});
			}
		}
	}

	/**
	 * Scan and determine slot content distribution.
	 * We do this during transclusion instead at compile time so that
	 * the distribution is decoupled from the compilation order of
	 * the slots.
	 *
	 * @param {Element|DocumentFragment} template
	 * @param {Element} content
	 * @param {Vue} vm
	 */

	function resolveSlots(vm, content) {
		if(!content) {
			return;
		}
		var contents = vm._slotContents = Object.create(null);
		var el, name;
		for(var i = 0, l = content.children.length; i < l; i++) {
			el = content.children[i];
			/* eslint-disable no-cond-assign */
			if(name = el.getAttribute('slot')) {
				(contents[name] || (contents[name] = [])).push(el);
			}
			/* eslint-enable no-cond-assign */
			if('development' !== 'production' && getBindAttr(el, 'slot')) {
				warn('The "slot" attribute must be static.', vm.$parent);
			}
		}
		for(name in contents) {
			contents[name] = extractFragment(contents[name], content);
		}
		if(content.hasChildNodes()) {
			var nodes = content.childNodes;
			if(nodes.length === 1 && nodes[0].nodeType === 3 && !nodes[0].data.trim()) {
				return;
			}
			contents['default'] = extractFragment(content.childNodes, content);
		}
	}

	/**
	 * Extract qualified content nodes from a node list.
	 *
	 * @param {NodeList} nodes
	 * @return {DocumentFragment}
	 */

	function extractFragment(nodes, parent) {
		var frag = document.createDocumentFragment();
		nodes = toArray(nodes);
		for(var i = 0, l = nodes.length; i < l; i++) {
			var node = nodes[i];
			if(isTemplate(node) && !node.hasAttribute('v-if') && !node.hasAttribute('v-for')) {
				parent.removeChild(node);
				node = parseTemplate(node, true);
			}
			frag.appendChild(node);
		}
		return frag;
	}

	var compiler = Object.freeze({
		compile: compile,
		compileAndLinkProps: compileAndLinkProps,
		compileRoot: compileRoot,
		transclude: transclude,
		resolveSlots: resolveSlots
	});

	function stateMixin(Vue) {
		/**
		 * Accessor for `$data` property, since setting $data
		 * requires observing the new object and updating
		 * proxied properties.
		 */

		Object.defineProperty(Vue.prototype, '$data', {
			get: function get() {
				return this._data;
			},
			set: function set(newData) {
				if(newData !== this._data) {
					this._setData(newData);
				}
			}
		});

		/**
		 * Setup the scope of an instance, which contains:
		 * - observed data
		 * - computed properties
		 * - user methods
		 * - meta properties
		 */

		Vue.prototype._initState = function() {
			this._initProps();
			this._initMeta();
			this._initMethods();
			this._initData();
			this._initComputed();
		};

		/**
		 * Initialize props.
		 */

		Vue.prototype._initProps = function() {
			var options = this.$options;
			var el = options.el;
			var props = options.props;
			if(props && !el) {
				'development' !== 'production' && warn('Props will not be compiled if no `el` option is ' + 'provided at instantiation.', this);
			}
			// make sure to convert string selectors into element now
			el = options.el = query(el);
			this._propsUnlinkFn = el && el.nodeType === 1 && props
				// props must be linked in proper scope if inside v-for
				?
				compileAndLinkProps(this, el, props, this._scope) : null;
		};

		/**
		 * Initialize the data.
		 */

		Vue.prototype._initData = function() {
			var dataFn = this.$options.data;
			var data = this._data = dataFn ? dataFn() : {};
			if(!isPlainObject(data)) {
				data = {};
				'development' !== 'production' && warn('data functions should return an object.', this);
			}
			var props = this._props;
			// proxy data on instance
			var keys = Object.keys(data);
			var i, key;
			i = keys.length;
			while(i--) {
				key = keys[i];
				// there are two scenarios where we can proxy a data key:
				// 1. it's not already defined as a prop
				// 2. it's provided via a instantiation option AND there are no
				//    template prop present
				if(!props || !hasOwn(props, key)) {
					this._proxy(key);
				} else if('development' !== 'production') {
					warn('Data field "' + key + '" is already defined ' + 'as a prop. To provide default value for a prop, use the "default" ' + 'prop option; if you want to pass prop values to an instantiation ' + 'call, use the "propsData" option.', this);
				}
			}
			// observe data
			observe(data, this);
		};

		/**
		 * Swap the instance's $data. Called in $data's setter.
		 *
		 * @param {Object} newData
		 */

		Vue.prototype._setData = function(newData) {
			newData = newData || {};
			var oldData = this._data;
			this._data = newData;
			var keys, key, i;
			// unproxy keys not present in new data
			keys = Object.keys(oldData);
			i = keys.length;
			while(i--) {
				key = keys[i];
				if(!(key in newData)) {
					this._unproxy(key);
				}
			}
			// proxy keys not already proxied,
			// and trigger change for changed values
			keys = Object.keys(newData);
			i = keys.length;
			while(i--) {
				key = keys[i];
				if(!hasOwn(this, key)) {
					// new property
					this._proxy(key);
				}
			}
			oldData.__ob__.removeVm(this);
			observe(newData, this);
			this._digest();
		};

		/**
		 * Proxy a property, so that
		 * vm.prop === vm._data.prop
		 *
		 * @param {String} key
		 */

		Vue.prototype._proxy = function(key) {
			if(!isReserved(key)) {
				// need to store ref to self here
				// because these getter/setters might
				// be called by child scopes via
				// prototype inheritance.
				var self = this;
				Object.defineProperty(self, key, {
					configurable: true,
					enumerable: true,
					get: function proxyGetter() {
						return self._data[key];
					},
					set: function proxySetter(val) {
						self._data[key] = val;
					}
				});
			}
		};

		/**
		 * Unproxy a property.
		 *
		 * @param {String} key
		 */

		Vue.prototype._unproxy = function(key) {
			if(!isReserved(key)) {
				delete this[key];
			}
		};

		/**
		 * Force update on every watcher in scope.
		 */

		Vue.prototype._digest = function() {
			for(var i = 0, l = this._watchers.length; i < l; i++) {
				this._watchers[i].update(true); // shallow updates
			}
		};

		/**
		 * Setup computed properties. They are essentially
		 * special getter/setters
		 */

		function noop() {}
		Vue.prototype._initComputed = function() {
			var computed = this.$options.computed;
			if(computed) {
				for(var key in computed) {
					var userDef = computed[key];
					var def = {
						enumerable: true,
						configurable: true
					};
					if(typeof userDef === 'function') {
						def.get = makeComputedGetter(userDef, this);
						def.set = noop;
					} else {
						def.get = userDef.get ? userDef.cache !== false ? makeComputedGetter(userDef.get, this) : bind(userDef.get, this) : noop;
						def.set = userDef.set ? bind(userDef.set, this) : noop;
					}
					Object.defineProperty(this, key, def);
				}
			}
		};

		function makeComputedGetter(getter, owner) {
			var watcher = new Watcher(owner, getter, null, {
				lazy: true
			});
			return function computedGetter() {
				if(watcher.dirty) {
					watcher.evaluate();
				}
				if(Dep.target) {
					watcher.depend();
				}
				return watcher.value;
			};
		}

		/**
		 * Setup instance methods. Methods must be bound to the
		 * instance since they might be passed down as a prop to
		 * child components.
		 */

		Vue.prototype._initMethods = function() {
			var methods = this.$options.methods;
			if(methods) {
				for(var key in methods) {
					this[key] = bind(methods[key], this);
				}
			}
		};

		/**
		 * Initialize meta information like $index, $key & $value.
		 */

		Vue.prototype._initMeta = function() {
			var metas = this.$options._meta;
			if(metas) {
				for(var key in metas) {
					defineReactive(this, key, metas[key]);
				}
			}
		};
	}

	var eventRE = /^v-on:|^@/;

	function eventsMixin(Vue) {
		/**
		 * Setup the instance's option events & watchers.
		 * If the value is a string, we pull it from the
		 * instance's methods by name.
		 */

		Vue.prototype._initEvents = function() {
			var options = this.$options;
			if(options._asComponent) {
				registerComponentEvents(this, options.el);
			}
			registerCallbacks(this, '$on', options.events);
			registerCallbacks(this, '$watch', options.watch);
		};

		/**
		 * Register v-on events on a child component
		 *
		 * @param {Vue} vm
		 * @param {Element} el
		 */

		function registerComponentEvents(vm, el) {
			var attrs = el.attributes;
			var name, value, handler;
			for(var i = 0, l = attrs.length; i < l; i++) {
				name = attrs[i].name;
				if(eventRE.test(name)) {
					name = name.replace(eventRE, '');
					// force the expression into a statement so that
					// it always dynamically resolves the method to call (#2670)
					// kinda ugly hack, but does the job.
					value = attrs[i].value;
					if(isSimplePath(value)) {
						value += '.apply(this, $arguments)';
					}
					handler = (vm._scope || vm._context).$eval(value, true);
					handler._fromParent = true;
					vm.$on(name.replace(eventRE), handler);
				}
			}
		}

		/**
		 * Register callbacks for option events and watchers.
		 *
		 * @param {Vue} vm
		 * @param {String} action
		 * @param {Object} hash
		 */

		function registerCallbacks(vm, action, hash) {
			if(!hash) return;
			var handlers, key, i, j;
			for(key in hash) {
				handlers = hash[key];
				if(isArray(handlers)) {
					for(i = 0, j = handlers.length; i < j; i++) {
						register(vm, action, key, handlers[i]);
					}
				} else {
					register(vm, action, key, handlers);
				}
			}
		}

		/**
		 * Helper to register an event/watch callback.
		 *
		 * @param {Vue} vm
		 * @param {String} action
		 * @param {String} key
		 * @param {Function|String|Object} handler
		 * @param {Object} [options]
		 */

		function register(vm, action, key, handler, options) {
			var type = typeof handler;
			if(type === 'function') {
				vm[action](key, handler, options);
			} else if(type === 'string') {
				var methods = vm.$options.methods;
				var method = methods && methods[handler];
				if(method) {
					vm[action](key, method, options);
				} else {
					'development' !== 'production' && warn('Unknown method: "' + handler + '" when ' + 'registering callback for ' + action + ': "' + key + '".', vm);
				}
			} else if(handler && type === 'object') {
				register(vm, action, key, handler.handler, handler);
			}
		}

		/**
		 * Setup recursive attached/detached calls
		 */

		Vue.prototype._initDOMHooks = function() {
			this.$on('hook:attached', onAttached);
			this.$on('hook:detached', onDetached);
		};

		/**
		 * Callback to recursively call attached hook on children
		 */

		function onAttached() {
			if(!this._isAttached) {
				this._isAttached = true;
				this.$children.forEach(callAttach);
			}
		}

		/**
		 * Iterator to call attached hook
		 *
		 * @param {Vue} child
		 */

		function callAttach(child) {
			if(!child._isAttached && inDoc(child.$el)) {
				child._callHook('attached');
			}
		}

		/**
		 * Callback to recursively call detached hook on children
		 */

		function onDetached() {
			if(this._isAttached) {
				this._isAttached = false;
				this.$children.forEach(callDetach);
			}
		}

		/**
		 * Iterator to call detached hook
		 *
		 * @param {Vue} child
		 */

		function callDetach(child) {
			if(child._isAttached && !inDoc(child.$el)) {
				child._callHook('detached');
			}
		}

		/**
		 * Trigger all handlers for a hook
		 *
		 * @param {String} hook
		 */

		Vue.prototype._callHook = function(hook) {
			this.$emit('pre-hook:' + hook);
			var handlers = this.$options[hook];
			if(handlers) {
				for(var i = 0, j = handlers.length; i < j; i++) {
					handlers[i].call(this);
				}
			}
			this.$emit('hook:' + hook);
		};
	}

	function noop() {}

	/**
	 * A directive links a DOM element with a piece of data,
	 * which is the result of evaluating an expression.
	 * It registers a watcher with the expression and calls
	 * the DOM update function when a change is triggered.
	 *
	 * @param {Object} descriptor
	 *                 - {String} name
	 *                 - {Object} def
	 *                 - {String} expression
	 *                 - {Array<Object>} [filters]
	 *                 - {Object} [modifiers]
	 *                 - {Boolean} literal
	 *                 - {String} attr
	 *                 - {String} arg
	 *                 - {String} raw
	 *                 - {String} [ref]
	 *                 - {Array<Object>} [interp]
	 *                 - {Boolean} [hasOneTime]
	 * @param {Vue} vm
	 * @param {Node} el
	 * @param {Vue} [host] - transclusion host component
	 * @param {Object} [scope] - v-for scope
	 * @param {Fragment} [frag] - owner fragment
	 * @constructor
	 */
	function Directive(descriptor, vm, el, host, scope, frag) {
		this.vm = vm;
		this.el = el;
		// copy descriptor properties
		this.descriptor = descriptor;
		this.name = descriptor.name;
		this.expression = descriptor.expression;
		this.arg = descriptor.arg;
		this.modifiers = descriptor.modifiers;
		this.filters = descriptor.filters;
		this.literal = this.modifiers && this.modifiers.literal;
		// private
		this._locked = false;
		this._bound = false;
		this._listeners = null;
		// link context
		this._host = host;
		this._scope = scope;
		this._frag = frag;
		// store directives on node in dev mode
		if('development' !== 'production' && this.el) {
			this.el._vue_directives = this.el._vue_directives || [];
			this.el._vue_directives.push(this);
		}
	}

	/**
	 * Initialize the directive, mixin definition properties,
	 * setup the watcher, call definition bind() and update()
	 * if present.
	 */

	Directive.prototype._bind = function() {
		var name = this.name;
		var descriptor = this.descriptor;

		// remove attribute
		if((name !== 'cloak' || this.vm._isCompiled) && this.el && this.el.removeAttribute) {
			var attr = descriptor.attr || 'v-' + name;
			this.el.removeAttribute(attr);
		}

		// copy def properties
		var def = descriptor.def;
		if(typeof def === 'function') {
			this.update = def;
		} else {
			extend(this, def);
		}

		// setup directive params
		this._setupParams();

		// initial bind
		if(this.bind) {
			this.bind();
		}
		this._bound = true;

		if(this.literal) {
			this.update && this.update(descriptor.raw);
		} else if((this.expression || this.modifiers) && (this.update || this.twoWay) && !this._checkStatement()) {
			// wrapped updater for context
			var dir = this;
			if(this.update) {
				this._update = function(val, oldVal) {
					if(!dir._locked) {
						dir.update(val, oldVal);
					}
				};
			} else {
				this._update = noop;
			}
			var preProcess = this._preProcess ? bind(this._preProcess, this) : null;
			var postProcess = this._postProcess ? bind(this._postProcess, this) : null;
			var watcher = this._watcher = new Watcher(this.vm, this.expression, this._update, // callback
				{
					filters: this.filters,
					twoWay: this.twoWay,
					deep: this.deep,
					preProcess: preProcess,
					postProcess: postProcess,
					scope: this._scope
				});
			// v-model with inital inline value need to sync back to
			// model instead of update to DOM on init. They would
			// set the afterBind hook to indicate that.
			if(this.afterBind) {
				this.afterBind();
			} else if(this.update) {
				this.update(watcher.value);
			}
		}
	};

	/**
	 * Setup all param attributes, e.g. track-by,
	 * transition-mode, etc...
	 */

	Directive.prototype._setupParams = function() {
		if(!this.params) {
			return;
		}
		var params = this.params;
		// swap the params array with a fresh object.
		this.params = Object.create(null);
		var i = params.length;
		var key, val, mappedKey;
		while(i--) {
			key = hyphenate(params[i]);
			mappedKey = camelize(key);
			val = getBindAttr(this.el, key);
			if(val != null) {
				// dynamic
				this._setupParamWatcher(mappedKey, val);
			} else {
				// static
				val = getAttr(this.el, key);
				if(val != null) {
					this.params[mappedKey] = val === '' ? true : val;
				}
			}
		}
	};

	/**
	 * Setup a watcher for a dynamic param.
	 *
	 * @param {String} key
	 * @param {String} expression
	 */

	Directive.prototype._setupParamWatcher = function(key, expression) {
		var self = this;
		var called = false;
		var unwatch = (this._scope || this.vm).$watch(expression, function(val, oldVal) {
			self.params[key] = val;
			// since we are in immediate mode,
			// only call the param change callbacks if this is not the first update.
			if(called) {
				var cb = self.paramWatchers && self.paramWatchers[key];
				if(cb) {
					cb.call(self, val, oldVal);
				}
			} else {
				called = true;
			}
		}, {
			immediate: true,
			user: false
		});
		(this._paramUnwatchFns || (this._paramUnwatchFns = [])).push(unwatch);
	};

	/**
	 * Check if the directive is a function caller
	 * and if the expression is a callable one. If both true,
	 * we wrap up the expression and use it as the event
	 * handler.
	 *
	 * e.g. on-click="a++"
	 *
	 * @return {Boolean}
	 */

	Directive.prototype._checkStatement = function() {
		var expression = this.expression;
		if(expression && this.acceptStatement && !isSimplePath(expression)) {
			var fn = parseExpression(expression).get;
			var scope = this._scope || this.vm;
			var handler = function handler(e) {
				scope.$event = e;
				fn.call(scope, scope);
				scope.$event = null;
			};
			if(this.filters) {
				handler = scope._applyFilters(handler, null, this.filters);
			}
			this.update(handler);
			return true;
		}
	};

	/**
	 * Set the corresponding value with the setter.
	 * This should only be used in two-way directives
	 * e.g. v-model.
	 *
	 * @param {*} value
	 * @public
	 */

	Directive.prototype.set = function(value) {
		/* istanbul ignore else */
		if(this.twoWay) {
			this._withLock(function() {
				this._watcher.set(value);
			});
		} else if('development' !== 'production') {
			warn('Directive.set() can only be used inside twoWay' + 'directives.');
		}
	};

	/**
	 * Execute a function while preventing that function from
	 * triggering updates on this directive instance.
	 *
	 * @param {Function} fn
	 */

	Directive.prototype._withLock = function(fn) {
		var self = this;
		self._locked = true;
		fn.call(self);
		nextTick(function() {
			self._locked = false;
		});
	};

	/**
	 * Convenience method that attaches a DOM event listener
	 * to the directive element and autometically tears it down
	 * during unbind.
	 *
	 * @param {String} event
	 * @param {Function} handler
	 * @param {Boolean} [useCapture]
	 */

	Directive.prototype.on = function(event, handler, useCapture) {
		on(this.el, event, handler, useCapture);
		(this._listeners || (this._listeners = [])).push([event, handler]);
	};

	/**
	 * Teardown the watcher and call unbind.
	 */

	Directive.prototype._teardown = function() {
		if(this._bound) {
			this._bound = false;
			if(this.unbind) {
				this.unbind();
			}
			if(this._watcher) {
				this._watcher.teardown();
			}
			var listeners = this._listeners;
			var i;
			if(listeners) {
				i = listeners.length;
				while(i--) {
					off(this.el, listeners[i][0], listeners[i][1]);
				}
			}
			var unwatchFns = this._paramUnwatchFns;
			if(unwatchFns) {
				i = unwatchFns.length;
				while(i--) {
					unwatchFns[i]();
				}
			}
			if('development' !== 'production' && this.el) {
				this.el._vue_directives.$remove(this);
			}
			this.vm = this.el = this._watcher = this._listeners = null;
		}
	};

	function lifecycleMixin(Vue) {
		/**
		 * Update v-ref for component.
		 *
		 * @param {Boolean} remove
		 */

		Vue.prototype._updateRef = function(remove) {
			var ref = this.$options._ref;
			if(ref) {
				var refs = (this._scope || this._context).$refs;
				if(remove) {
					if(refs[ref] === this) {
						refs[ref] = null;
					}
				} else {
					refs[ref] = this;
				}
			}
		};

		/**
		 * Transclude, compile and link element.
		 *
		 * If a pre-compiled linker is available, that means the
		 * passed in element will be pre-transcluded and compiled
		 * as well - all we need to do is to call the linker.
		 *
		 * Otherwise we need to call transclude/compile/link here.
		 *
		 * @param {Element} el
		 */

		Vue.prototype._compile = function(el) {
			var options = this.$options;

			// transclude and init element
			// transclude can potentially replace original
			// so we need to keep reference; this step also injects
			// the template and caches the original attributes
			// on the container node and replacer node.
			var original = el;
			el = transclude(el, options);
			this._initElement(el);

			// handle v-pre on root node (#2026)
			if(el.nodeType === 1 && getAttr(el, 'v-pre') !== null) {
				return;
			}

			// root is always compiled per-instance, because
			// container attrs and props can be different every time.
			var contextOptions = this._context && this._context.$options;
			var rootLinker = compileRoot(el, options, contextOptions);

			// resolve slot distribution
			resolveSlots(this, options._content);

			// compile and link the rest
			var contentLinkFn;
			var ctor = this.constructor;
			// component compilation can be cached
			// as long as it's not using inline-template
			if(options._linkerCachable) {
				contentLinkFn = ctor.linker;
				if(!contentLinkFn) {
					contentLinkFn = ctor.linker = compile(el, options);
				}
			}

			// link phase
			// make sure to link root with prop scope!
			var rootUnlinkFn = rootLinker(this, el, this._scope);
			var contentUnlinkFn = contentLinkFn ? contentLinkFn(this, el) : compile(el, options)(this, el);

			// register composite unlink function
			// to be called during instance destruction
			this._unlinkFn = function() {
				rootUnlinkFn();
				// passing destroying: true to avoid searching and
				// splicing the directives
				contentUnlinkFn(true);
			};

			// finally replace original
			if(options.replace) {
				replace(original, el);
			}

			this._isCompiled = true;
			this._callHook('compiled');
		};

		/**
		 * Initialize instance element. Called in the public
		 * $mount() method.
		 *
		 * @param {Element} el
		 */

		Vue.prototype._initElement = function(el) {
			if(isFragment(el)) {
				this._isFragment = true;
				this.$el = this._fragmentStart = el.firstChild;
				this._fragmentEnd = el.lastChild;
				// set persisted text anchors to empty
				if(this._fragmentStart.nodeType === 3) {
					this._fragmentStart.data = this._fragmentEnd.data = '';
				}
				this._fragment = el;
			} else {
				this.$el = el;
			}
			this.$el.__vue__ = this;
			this._callHook('beforeCompile');
		};

		/**
		 * Create and bind a directive to an element.
		 *
		 * @param {Object} descriptor - parsed directive descriptor
		 * @param {Node} node   - target node
		 * @param {Vue} [host] - transclusion host component
		 * @param {Object} [scope] - v-for scope
		 * @param {Fragment} [frag] - owner fragment
		 */

		Vue.prototype._bindDir = function(descriptor, node, host, scope, frag) {
			this._directives.push(new Directive(descriptor, this, node, host, scope, frag));
		};

		/**
		 * Teardown an instance, unobserves the data, unbind all the
		 * directives, turn off all the event listeners, etc.
		 *
		 * @param {Boolean} remove - whether to remove the DOM node.
		 * @param {Boolean} deferCleanup - if true, defer cleanup to
		 *                                 be called later
		 */

		Vue.prototype._destroy = function(remove, deferCleanup) {
			if(this._isBeingDestroyed) {
				if(!deferCleanup) {
					this._cleanup();
				}
				return;
			}

			var destroyReady;
			var pendingRemoval;

			var self = this;
			// Cleanup should be called either synchronously or asynchronoysly as
			// callback of this.$remove(), or if remove and deferCleanup are false.
			// In any case it should be called after all other removing, unbinding and
			// turning of is done
			var cleanupIfPossible = function cleanupIfPossible() {
				if(destroyReady && !pendingRemoval && !deferCleanup) {
					self._cleanup();
				}
			};

			// remove DOM element
			if(remove && this.$el) {
				pendingRemoval = true;
				this.$remove(function() {
					pendingRemoval = false;
					cleanupIfPossible();
				});
			}

			this._callHook('beforeDestroy');
			this._isBeingDestroyed = true;
			var i;
			// remove self from parent. only necessary
			// if parent is not being destroyed as well.
			var parent = this.$parent;
			if(parent && !parent._isBeingDestroyed) {
				parent.$children.$remove(this);
				// unregister ref (remove: true)
				this._updateRef(true);
			}
			// destroy all children.
			i = this.$children.length;
			while(i--) {
				this.$children[i].$destroy();
			}
			// teardown props
			if(this._propsUnlinkFn) {
				this._propsUnlinkFn();
			}
			// teardown all directives. this also tearsdown all
			// directive-owned watchers.
			if(this._unlinkFn) {
				this._unlinkFn();
			}
			i = this._watchers.length;
			while(i--) {
				this._watchers[i].teardown();
			}
			// remove reference to self on $el
			if(this.$el) {
				this.$el.__vue__ = null;
			}

			destroyReady = true;
			cleanupIfPossible();
		};

		/**
		 * Clean up to ensure garbage collection.
		 * This is called after the leave transition if there
		 * is any.
		 */

		Vue.prototype._cleanup = function() {
			if(this._isDestroyed) {
				return;
			}
			// remove self from owner fragment
			// do it in cleanup so that we can call $destroy with
			// defer right when a fragment is about to be removed.
			if(this._frag) {
				this._frag.children.$remove(this);
			}
			// remove reference from data ob
			// frozen object may not have observer.
			if(this._data && this._data.__ob__) {
				this._data.__ob__.removeVm(this);
			}
			// Clean up references to private properties and other
			// instances. preserve reference to _data so that proxy
			// accessors still work. The only potential side effect
			// here is that mutating the instance after it's destroyed
			// may affect the state of other components that are still
			// observing the same object, but that seems to be a
			// reasonable responsibility for the user rather than
			// always throwing an error on them.
			this.$el = this.$parent = this.$root = this.$children = this._watchers = this._context = this._scope = this._directives = null;
			// call the last hook...
			this._isDestroyed = true;
			this._callHook('destroyed');
			// turn off all instance listeners.
			this.$off();
		};
	}

	function miscMixin(Vue) {
		/**
		 * Apply a list of filter (descriptors) to a value.
		 * Using plain for loops here because this will be called in
		 * the getter of any watcher with filters so it is very
		 * performance sensitive.
		 *
		 * @param {*} value
		 * @param {*} [oldValue]
		 * @param {Array} filters
		 * @param {Boolean} write
		 * @return {*}
		 */

		Vue.prototype._applyFilters = function(value, oldValue, filters, write) {
			var filter, fn, args, arg, offset, i, l, j, k;
			for(i = 0, l = filters.length; i < l; i++) {
				filter = filters[write ? l - i - 1 : i];
				fn = resolveAsset(this.$options, 'filters', filter.name, true);
				if(!fn) continue;
				fn = write ? fn.write : fn.read || fn;
				if(typeof fn !== 'function') continue;
				args = write ? [value, oldValue] : [value];
				offset = write ? 2 : 1;
				if(filter.args) {
					for(j = 0, k = filter.args.length; j < k; j++) {
						arg = filter.args[j];
						args[j + offset] = arg.dynamic ? this.$get(arg.value) : arg.value;
					}
				}
				value = fn.apply(this, args);
			}
			return value;
		};

		/**
		 * Resolve a component, depending on whether the component
		 * is defined normally or using an async factory function.
		 * Resolves synchronously if already resolved, otherwise
		 * resolves asynchronously and caches the resolved
		 * constructor on the factory.
		 *
		 * @param {String|Function} value
		 * @param {Function} cb
		 */

		Vue.prototype._resolveComponent = function(value, cb) {
			var factory;
			if(typeof value === 'function') {
				factory = value;
			} else {
				factory = resolveAsset(this.$options, 'components', value, true);
			}
			/* istanbul ignore if */
			if(!factory) {
				return;
			}
			// async component factory
			if(!factory.options) {
				if(factory.resolved) {
					// cached
					cb(factory.resolved);
				} else if(factory.requested) {
					// pool callbacks
					factory.pendingCallbacks.push(cb);
				} else {
					factory.requested = true;
					var cbs = factory.pendingCallbacks = [cb];
					factory.call(this, function resolve(res) {
						if(isPlainObject(res)) {
							res = Vue.extend(res);
						}
						// cache resolved
						factory.resolved = res;
						// invoke callbacks
						for(var i = 0, l = cbs.length; i < l; i++) {
							cbs[i](res);
						}
					}, function reject(reason) {
						'development' !== 'production' && warn('Failed to resolve async component' + (typeof value === 'string' ? ': ' + value : '') + '. ' + (reason ? '\nReason: ' + reason : ''));
					});
				}
			} else {
				// normal component
				cb(factory);
			}
		};
	}

	var filterRE$1 = /[^|]\|[^|]/;

	function dataAPI(Vue) {
		/**
		 * Get the value from an expression on this vm.
		 *
		 * @param {String} exp
		 * @param {Boolean} [asStatement]
		 * @return {*}
		 */

		Vue.prototype.$get = function(exp, asStatement) {
			var res = parseExpression(exp);
			if(res) {
				if(asStatement) {
					var self = this;
					return function statementHandler() {
						self.$arguments = toArray(arguments);
						var result = res.get.call(self, self);
						self.$arguments = null;
						return result;
					};
				} else {
					try {
						return res.get.call(this, this);
					} catch(e) {}
				}
			}
		};

		/**
		 * Set the value from an expression on this vm.
		 * The expression must be a valid left-hand
		 * expression in an assignment.
		 *
		 * @param {String} exp
		 * @param {*} val
		 */

		Vue.prototype.$set = function(exp, val) {
			var res = parseExpression(exp, true);
			if(res && res.set) {
				res.set.call(this, this, val);
			}
		};

		/**
		 * Delete a property on the VM
		 *
		 * @param {String} key
		 */

		Vue.prototype.$delete = function(key) {
			del(this._data, key);
		};

		/**
		 * Watch an expression, trigger callback when its
		 * value changes.
		 *
		 * @param {String|Function} expOrFn
		 * @param {Function} cb
		 * @param {Object} [options]
		 *                 - {Boolean} deep
		 *                 - {Boolean} immediate
		 * @return {Function} - unwatchFn
		 */

		Vue.prototype.$watch = function(expOrFn, cb, options) {
			var vm = this;
			var parsed;
			if(typeof expOrFn === 'string') {
				parsed = parseDirective(expOrFn);
				expOrFn = parsed.expression;
			}
			var watcher = new Watcher(vm, expOrFn, cb, {
				deep: options && options.deep,
				sync: options && options.sync,
				filters: parsed && parsed.filters,
				user: !options || options.user !== false
			});
			if(options && options.immediate) {
				cb.call(vm, watcher.value);
			}
			return function unwatchFn() {
				watcher.teardown();
			};
		};

		/**
		 * Evaluate a text directive, including filters.
		 *
		 * @param {String} text
		 * @param {Boolean} [asStatement]
		 * @return {String}
		 */

		Vue.prototype.$eval = function(text, asStatement) {
			// check for filters.
			if(filterRE$1.test(text)) {
				var dir = parseDirective(text);
				// the filter regex check might give false positive
				// for pipes inside strings, so it's possible that
				// we don't get any filters here
				var val = this.$get(dir.expression, asStatement);
				return dir.filters ? this._applyFilters(val, null, dir.filters) : val;
			} else {
				// no filter
				return this.$get(text, asStatement);
			}
		};

		/**
		 * Interpolate a piece of template text.
		 *
		 * @param {String} text
		 * @return {String}
		 */

		Vue.prototype.$interpolate = function(text) {
			var tokens = parseText(text);
			var vm = this;
			if(tokens) {
				if(tokens.length === 1) {
					return vm.$eval(tokens[0].value) + '';
				} else {
					return tokens.map(function(token) {
						return token.tag ? vm.$eval(token.value) : token.value;
					}).join('');
				}
			} else {
				return text;
			}
		};

		/**
		 * Log instance data as a plain JS object
		 * so that it is easier to inspect in console.
		 * This method assumes console is available.
		 *
		 * @param {String} [path]
		 */

		Vue.prototype.$log = function(path) {
			var data = path ? getPath(this._data, path) : this._data;
			if(data) {
				data = clean(data);
			}
			// include computed fields
			if(!path) {
				var key;
				for(key in this.$options.computed) {
					data[key] = clean(this[key]);
				}
				if(this._props) {
					for(key in this._props) {
						data[key] = clean(this[key]);
					}
				}
			}
			console.log(data);
		};

		/**
		 * "clean" a getter/setter converted object into a plain
		 * object copy.
		 *
		 * @param {Object} - obj
		 * @return {Object}
		 */

		function clean(obj) {
			return JSON.parse(JSON.stringify(obj));
		}
	}

	function domAPI(Vue) {
		/**
		 * Convenience on-instance nextTick. The callback is
		 * auto-bound to the instance, and this avoids component
		 * modules having to rely on the global Vue.
		 *
		 * @param {Function} fn
		 */

		Vue.prototype.$nextTick = function(fn) {
			nextTick(fn, this);
		};

		/**
		 * Append instance to target
		 *
		 * @param {Node} target
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition] - defaults to true
		 */

		Vue.prototype.$appendTo = function(target, cb, withTransition) {
			return insert(this, target, cb, withTransition, append, appendWithTransition);
		};

		/**
		 * Prepend instance to target
		 *
		 * @param {Node} target
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition] - defaults to true
		 */

		Vue.prototype.$prependTo = function(target, cb, withTransition) {
			target = query(target);
			if(target.hasChildNodes()) {
				this.$before(target.firstChild, cb, withTransition);
			} else {
				this.$appendTo(target, cb, withTransition);
			}
			return this;
		};

		/**
		 * Insert instance before target
		 *
		 * @param {Node} target
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition] - defaults to true
		 */

		Vue.prototype.$before = function(target, cb, withTransition) {
			return insert(this, target, cb, withTransition, beforeWithCb, beforeWithTransition);
		};

		/**
		 * Insert instance after target
		 *
		 * @param {Node} target
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition] - defaults to true
		 */

		Vue.prototype.$after = function(target, cb, withTransition) {
			target = query(target);
			if(target.nextSibling) {
				this.$before(target.nextSibling, cb, withTransition);
			} else {
				this.$appendTo(target.parentNode, cb, withTransition);
			}
			return this;
		};

		/**
		 * Remove instance from DOM
		 *
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition] - defaults to true
		 */

		Vue.prototype.$remove = function(cb, withTransition) {
			if(!this.$el.parentNode) {
				return cb && cb();
			}
			var inDocument = this._isAttached && inDoc(this.$el);
			// if we are not in document, no need to check
			// for transitions
			if(!inDocument) withTransition = false;
			var self = this;
			var realCb = function realCb() {
				if(inDocument) self._callHook('detached');
				if(cb) cb();
			};
			if(this._isFragment) {
				removeNodeRange(this._fragmentStart, this._fragmentEnd, this, this._fragment, realCb);
			} else {
				var op = withTransition === false ? removeWithCb : removeWithTransition;
				op(this.$el, this, realCb);
			}
			return this;
		};

		/**
		 * Shared DOM insertion function.
		 *
		 * @param {Vue} vm
		 * @param {Element} target
		 * @param {Function} [cb]
		 * @param {Boolean} [withTransition]
		 * @param {Function} op1 - op for non-transition insert
		 * @param {Function} op2 - op for transition insert
		 * @return vm
		 */

		function insert(vm, target, cb, withTransition, op1, op2) {
			target = query(target);
			var targetIsDetached = !inDoc(target);
			var op = withTransition === false || targetIsDetached ? op1 : op2;
			var shouldCallHook = !targetIsDetached && !vm._isAttached && !inDoc(vm.$el);
			if(vm._isFragment) {
				mapNodeRange(vm._fragmentStart, vm._fragmentEnd, function(node) {
					op(node, target, vm);
				});
				cb && cb();
			} else {
				op(vm.$el, target, vm, cb);
			}
			if(shouldCallHook) {
				vm._callHook('attached');
			}
			return vm;
		}

		/**
		 * Check for selectors
		 *
		 * @param {String|Element} el
		 */

		function query(el) {
			return typeof el === 'string' ? document.querySelector(el) : el;
		}

		/**
		 * Append operation that takes a callback.
		 *
		 * @param {Node} el
		 * @param {Node} target
		 * @param {Vue} vm - unused
		 * @param {Function} [cb]
		 */

		function append(el, target, vm, cb) {
			target.appendChild(el);
			if(cb) cb();
		}

		/**
		 * InsertBefore operation that takes a callback.
		 *
		 * @param {Node} el
		 * @param {Node} target
		 * @param {Vue} vm - unused
		 * @param {Function} [cb]
		 */

		function beforeWithCb(el, target, vm, cb) {
			before(el, target);
			if(cb) cb();
		}

		/**
		 * Remove operation that takes a callback.
		 *
		 * @param {Node} el
		 * @param {Vue} vm - unused
		 * @param {Function} [cb]
		 */

		function removeWithCb(el, vm, cb) {
			remove(el);
			if(cb) cb();
		}
	}

	function eventsAPI(Vue) {
		/**
		 * Listen on the given `event` with `fn`.
		 *
		 * @param {String} event
		 * @param {Function} fn
		 */

		Vue.prototype.$on = function(event, fn) {
			(this._events[event] || (this._events[event] = [])).push(fn);
			modifyListenerCount(this, event, 1);
			return this;
		};

		/**
		 * Adds an `event` listener that will be invoked a single
		 * time then automatically removed.
		 *
		 * @param {String} event
		 * @param {Function} fn
		 */

		Vue.prototype.$once = function(event, fn) {
			var self = this;

			function on() {
				self.$off(event, on);
				fn.apply(this, arguments);
			}
			on.fn = fn;
			this.$on(event, on);
			return this;
		};

		/**
		 * Remove the given callback for `event` or all
		 * registered callbacks.
		 *
		 * @param {String} event
		 * @param {Function} fn
		 */

		Vue.prototype.$off = function(event, fn) {
			var cbs;
			// all
			if(!arguments.length) {
				if(this.$parent) {
					for(event in this._events) {
						cbs = this._events[event];
						if(cbs) {
							modifyListenerCount(this, event, -cbs.length);
						}
					}
				}
				this._events = {};
				return this;
			}
			// specific event
			cbs = this._events[event];
			if(!cbs) {
				return this;
			}
			if(arguments.length === 1) {
				modifyListenerCount(this, event, -cbs.length);
				this._events[event] = null;
				return this;
			}
			// specific handler
			var cb;
			var i = cbs.length;
			while(i--) {
				cb = cbs[i];
				if(cb === fn || cb.fn === fn) {
					modifyListenerCount(this, event, -1);
					cbs.splice(i, 1);
					break;
				}
			}
			return this;
		};

		/**
		 * Trigger an event on self.
		 *
		 * @param {String|Object} event
		 * @return {Boolean} shouldPropagate
		 */

		Vue.prototype.$emit = function(event) {
			var isSource = typeof event === 'string';
			event = isSource ? event : event.name;
			var cbs = this._events[event];
			var shouldPropagate = isSource || !cbs;
			if(cbs) {
				cbs = cbs.length > 1 ? toArray(cbs) : cbs;
				// this is a somewhat hacky solution to the question raised
				// in #2102: for an inline component listener like <comp @test="doThis">,
				// the propagation handling is somewhat broken. Therefore we
				// need to treat these inline callbacks differently.
				var hasParentCbs = isSource && cbs.some(function(cb) {
					return cb._fromParent;
				});
				if(hasParentCbs) {
					shouldPropagate = false;
				}
				var args = toArray(arguments, 1);
				for(var i = 0, l = cbs.length; i < l; i++) {
					var cb = cbs[i];
					var res = cb.apply(this, args);
					if(res === true && (!hasParentCbs || cb._fromParent)) {
						shouldPropagate = true;
					}
				}
			}
			return shouldPropagate;
		};

		/**
		 * Recursively broadcast an event to all children instances.
		 *
		 * @param {String|Object} event
		 * @param {...*} additional arguments
		 */

		Vue.prototype.$broadcast = function(event) {
			var isSource = typeof event === 'string';
			event = isSource ? event : event.name;
			// if no child has registered for this event,
			// then there's no need to broadcast.
			if(!this._eventsCount[event]) return;
			var children = this.$children;
			var args = toArray(arguments);
			if(isSource) {
				// use object event to indicate non-source emit
				// on children
				args[0] = { name: event, source: this };
			}
			for(var i = 0, l = children.length; i < l; i++) {
				var child = children[i];
				var shouldPropagate = child.$emit.apply(child, args);
				if(shouldPropagate) {
					child.$broadcast.apply(child, args);
				}
			}
			return this;
		};

		/**
		 * Recursively propagate an event up the parent chain.
		 *
		 * @param {String} event
		 * @param {...*} additional arguments
		 */

		Vue.prototype.$dispatch = function(event) {
			var shouldPropagate = this.$emit.apply(this, arguments);
			if(!shouldPropagate) return;
			var parent = this.$parent;
			var args = toArray(arguments);
			// use object event to indicate non-source emit
			// on parents
			args[0] = { name: event, source: this };
			while(parent) {
				shouldPropagate = parent.$emit.apply(parent, args);
				parent = shouldPropagate ? parent.$parent : null;
			}
			return this;
		};

		/**
		 * Modify the listener counts on all parents.
		 * This bookkeeping allows $broadcast to return early when
		 * no child has listened to a certain event.
		 *
		 * @param {Vue} vm
		 * @param {String} event
		 * @param {Number} count
		 */

		var hookRE = /^hook:/;

		function modifyListenerCount(vm, event, count) {
			var parent = vm.$parent;
			// hooks do not get broadcasted so no need
			// to do bookkeeping for them
			if(!parent || !count || hookRE.test(event)) return;
			while(parent) {
				parent._eventsCount[event] = (parent._eventsCount[event] || 0) + count;
				parent = parent.$parent;
			}
		}
	}

	function lifecycleAPI(Vue) {
		/**
		 * Set instance target element and kick off the compilation
		 * process. The passed in `el` can be a selector string, an
		 * existing Element, or a DocumentFragment (for block
		 * instances).
		 *
		 * @param {Element|DocumentFragment|string} el
		 * @public
		 */

		Vue.prototype.$mount = function(el) {
			if(this._isCompiled) {
				'development' !== 'production' && warn('$mount() should be called only once.', this);
				return;
			}
			el = query(el);
			if(!el) {
				el = document.createElement('div');
			}
			this._compile(el);
			this._initDOMHooks();
			if(inDoc(this.$el)) {
				this._callHook('attached');
				ready.call(this);
			} else {
				this.$once('hook:attached', ready);
			}
			return this;
		};

		/**
		 * Mark an instance as ready.
		 */

		function ready() {
			this._isAttached = true;
			this._isReady = true;
			this._callHook('ready');
		}

		/**
		 * Teardown the instance, simply delegate to the internal
		 * _destroy.
		 *
		 * @param {Boolean} remove
		 * @param {Boolean} deferCleanup
		 */

		Vue.prototype.$destroy = function(remove, deferCleanup) {
			this._destroy(remove, deferCleanup);
		};

		/**
		 * Partially compile a piece of DOM and return a
		 * decompile function.
		 *
		 * @param {Element|DocumentFragment} el
		 * @param {Vue} [host]
		 * @param {Object} [scope]
		 * @param {Fragment} [frag]
		 * @return {Function}
		 */

		Vue.prototype.$compile = function(el, host, scope, frag) {
			return compile(el, this.$options, true)(this, el, host, scope, frag);
		};
	}

	/**
	 * The exposed Vue constructor.
	 *
	 * API conventions:
	 * - public API methods/properties are prefixed with `$`
	 * - internal methods/properties are prefixed with `_`
	 * - non-prefixed properties are assumed to be proxied user
	 *   data.
	 *
	 * @constructor
	 * @param {Object} [options]
	 * @public
	 */

	function Vue(options) {
		this._init(options);
	}

	// install internals
	initMixin(Vue);
	stateMixin(Vue);
	eventsMixin(Vue);
	lifecycleMixin(Vue);
	miscMixin(Vue);

	// install instance APIs
	dataAPI(Vue);
	domAPI(Vue);
	eventsAPI(Vue);
	lifecycleAPI(Vue);

	var slot = {

		priority: SLOT,
		params: ['name'],

		bind: function bind() {
			// this was resolved during component transclusion
			var name = this.params.name || 'default';
			var content = this.vm._slotContents && this.vm._slotContents[name];
			if(!content || !content.hasChildNodes()) {
				this.fallback();
			} else {
				this.compile(content.cloneNode(true), this.vm._context, this.vm);
			}
		},

		compile: function compile(content, context, host) {
			if(content && context) {
				if(this.el.hasChildNodes() && content.childNodes.length === 1 && content.childNodes[0].nodeType === 1 && content.childNodes[0].hasAttribute('v-if')) {
					// if the inserted slot has v-if
					// inject fallback content as the v-else
					var elseBlock = document.createElement('template');
					elseBlock.setAttribute('v-else', '');
					elseBlock.innerHTML = this.el.innerHTML;
					// the else block should be compiled in child scope
					elseBlock._context = this.vm;
					content.appendChild(elseBlock);
				}
				var scope = host ? host._scope : this._scope;
				this.unlink = context.$compile(content, host, scope, this._frag);
			}
			if(content) {
				replace(this.el, content);
			} else {
				remove(this.el);
			}
		},

		fallback: function fallback() {
			this.compile(extractContent(this.el, true), this.vm);
		},

		unbind: function unbind() {
			if(this.unlink) {
				this.unlink();
			}
		}
	};

	var partial = {

		priority: PARTIAL,

		params: ['name'],

		// watch changes to name for dynamic partials
		paramWatchers: {
			name: function name(value) {
				vIf.remove.call(this);
				if(value) {
					this.insert(value);
				}
			}
		},

		bind: function bind() {
			this.anchor = createAnchor('v-partial');
			replace(this.el, this.anchor);
			this.insert(this.params.name);
		},

		insert: function insert(id) {
			var partial = resolveAsset(this.vm.$options, 'partials', id, true);
			if(partial) {
				this.factory = new FragmentFactory(this.vm, partial);
				vIf.insert.call(this);
			}
		},

		unbind: function unbind() {
			if(this.frag) {
				this.frag.destroy();
			}
		}
	};

	var elementDirectives = {
		slot: slot,
		partial: partial
	};

	var convertArray = vFor._postProcess;

	/**
	 * Limit filter for arrays
	 *
	 * @param {Number} n
	 * @param {Number} offset (Decimal expected)
	 */

	function limitBy(arr, n, offset) {
		offset = offset ? parseInt(offset, 10) : 0;
		n = toNumber(n);
		return typeof n === 'number' ? arr.slice(offset, offset + n) : arr;
	}

	/**
	 * Filter filter for arrays
	 *
	 * @param {String} search
	 * @param {String} [delimiter]
	 * @param {String} ...dataKeys
	 */

	function filterBy(arr, search, delimiter) {
		arr = convertArray(arr);
		if(search == null) {
			return arr;
		}
		if(typeof search === 'function') {
			return arr.filter(search);
		}
		// cast to lowercase string
		search = ('' + search).toLowerCase();
		// allow optional `in` delimiter
		// because why not
		var n = delimiter === 'in' ? 3 : 2;
		// extract and flatten keys
		var keys = Array.prototype.concat.apply([], toArray(arguments, n));
		var res = [];
		var item, key, val, j;
		for(var i = 0, l = arr.length; i < l; i++) {
			item = arr[i];
			val = item && item.$value || item;
			j = keys.length;
			if(j) {
				while(j--) {
					key = keys[j];
					if(key === '$key' && contains(item.$key, search) || contains(getPath(val, key), search)) {
						res.push(item);
						break;
					}
				}
			} else if(contains(item, search)) {
				res.push(item);
			}
		}
		return res;
	}

	/**
	 * Filter filter for arrays
	 *
	 * @param {String|Array<String>|Function} ...sortKeys
	 * @param {Number} [order]
	 */

	function orderBy(arr) {
		var comparator = null;
		var sortKeys = undefined;
		arr = convertArray(arr);

		// determine order (last argument)
		var args = toArray(arguments, 1);
		var order = args[args.length - 1];
		if(typeof order === 'number') {
			order = order < 0 ? -1 : 1;
			args = args.length > 1 ? args.slice(0, -1) : args;
		} else {
			order = 1;
		}

		// determine sortKeys & comparator
		var firstArg = args[0];
		if(!firstArg) {
			return arr;
		} else if(typeof firstArg === 'function') {
			// custom comparator
			comparator = function(a, b) {
				return firstArg(a, b) * order;
			};
		} else {
			// string keys. flatten first
			sortKeys = Array.prototype.concat.apply([], args);
			comparator = function(a, b, i) {
				i = i || 0;
				return i >= sortKeys.length - 1 ? baseCompare(a, b, i) : baseCompare(a, b, i) || comparator(a, b, i + 1);
			};
		}

		function baseCompare(a, b, sortKeyIndex) {
			var sortKey = sortKeys[sortKeyIndex];
			if(sortKey) {
				if(sortKey !== '$key') {
					if(isObject(a) && '$value' in a) a = a.$value;
					if(isObject(b) && '$value' in b) b = b.$value;
				}
				a = isObject(a) ? getPath(a, sortKey) : a;
				b = isObject(b) ? getPath(b, sortKey) : b;
			}
			return a === b ? 0 : a > b ? order : -order;
		}

		// sort on a copy to avoid mutating original array
		return arr.slice().sort(comparator);
	}

	/**
	 * String contain helper
	 *
	 * @param {*} val
	 * @param {String} search
	 */

	function contains(val, search) {
		var i;
		if(isPlainObject(val)) {
			var keys = Object.keys(val);
			i = keys.length;
			while(i--) {
				if(contains(val[keys[i]], search)) {
					return true;
				}
			}
		} else if(isArray(val)) {
			i = val.length;
			while(i--) {
				if(contains(val[i], search)) {
					return true;
				}
			}
		} else if(val != null) {
			return val.toString().toLowerCase().indexOf(search) > -1;
		}
	}

	var digitsRE = /(\d{3})(?=\d)/g;

	// asset collections must be a plain object.
	var filters = {

		orderBy: orderBy,
		filterBy: filterBy,
		limitBy: limitBy,

		/**
		 * Stringify value.
		 *
		 * @param {Number} indent
		 */

		json: {
			read: function read(value, indent) {
				return typeof value === 'string' ? value : JSON.stringify(value, null, Number(indent) || 2);
			},
			write: function write(value) {
				try {
					return JSON.parse(value);
				} catch(e) {
					return value;
				}
			}
		},

		/**
		 * 'abc' => 'Abc'
		 */

		capitalize: function capitalize(value) {
			if(!value && value !== 0) return '';
			value = value.toString();
			return value.charAt(0).toUpperCase() + value.slice(1);
		},

		/**
		 * 'abc' => 'ABC'
		 */

		uppercase: function uppercase(value) {
			return value || value === 0 ? value.toString().toUpperCase() : '';
		},

		/**
		 * 'AbC' => 'abc'
		 */

		lowercase: function lowercase(value) {
			return value || value === 0 ? value.toString().toLowerCase() : '';
		},

		/**
		 * 12345 => $12,345.00
		 *
		 * @param {String} sign
		 * @param {Number} decimals Decimal places
		 */

		currency: function currency(value, _currency, decimals) {
			value = parseFloat(value);
			if(!isFinite(value) || !value && value !== 0) return '';
			_currency = _currency != null ? _currency : '$';
			decimals = decimals != null ? decimals : 2;
			var stringified = Math.abs(value).toFixed(decimals);
			var _int = decimals ? stringified.slice(0, -1 - decimals) : stringified;
			var i = _int.length % 3;
			var head = i > 0 ? _int.slice(0, i) + (_int.length > 3 ? ',' : '') : '';
			var _float = decimals ? stringified.slice(-1 - decimals) : '';
			var sign = value < 0 ? '-' : '';
			return sign + _currency + head + _int.slice(i).replace(digitsRE, '$1,') + _float;
		},

		/**
		 * 'item' => 'items'
		 *
		 * @params
		 *  an array of strings corresponding to
		 *  the single, double, triple ... forms of the word to
		 *  be pluralized. When the number to be pluralized
		 *  exceeds the length of the args, it will use the last
		 *  entry in the array.
		 *
		 *  e.g. ['single', 'double', 'triple', 'multiple']
		 */

		pluralize: function pluralize(value) {
			var args = toArray(arguments, 1);
			return args.length > 1 ? args[value % 10 - 1] || args[args.length - 1] : args[0] + (value === 1 ? '' : 's');
		},

		/**
		 * Debounce a handler function.
		 *
		 * @param {Function} handler
		 * @param {Number} delay = 300
		 * @return {Function}
		 */

		debounce: function debounce(handler, delay) {
			if(!handler) return;
			if(!delay) {
				delay = 300;
			}
			return _debounce(handler, delay);
		}
	};

	function installGlobalAPI(Vue) {
		/**
		 * Vue and every constructor that extends Vue has an
		 * associated options object, which can be accessed during
		 * compilation steps as `this.constructor.options`.
		 *
		 * These can be seen as the default options of every
		 * Vue instance.
		 */

		Vue.options = {
			directives: directives,
			elementDirectives: elementDirectives,
			filters: filters,
			transitions: {},
			components: {},
			partials: {},
			replace: true
		};

		/**
		 * Expose useful internals
		 */

		Vue.util = util;
		Vue.config = config;
		Vue.set = set;
		Vue['delete'] = del;
		Vue.nextTick = nextTick;

		/**
		 * The following are exposed for advanced usage / plugins
		 */

		Vue.compiler = compiler;
		Vue.FragmentFactory = FragmentFactory;
		Vue.internalDirectives = internalDirectives;
		Vue.parsers = {
			path: path,
			text: text,
			template: template,
			directive: directive,
			expression: expression
		};

		/**
		 * Each instance constructor, including Vue, has a unique
		 * cid. This enables us to create wrapped "child
		 * constructors" for prototypal inheritance and cache them.
		 */

		Vue.cid = 0;
		var cid = 1;

		/**
		 * Class inheritance
		 *
		 * @param {Object} extendOptions
		 */

		Vue.extend = function(extendOptions) {
			extendOptions = extendOptions || {};
			var Super = this;
			var isFirstExtend = Super.cid === 0;
			if(isFirstExtend && extendOptions._Ctor) {
				return extendOptions._Ctor;
			}
			var name = extendOptions.name || Super.options.name;
			if('development' !== 'production') {
				if(!/^[a-zA-Z][\w-]*$/.test(name)) {
					warn('Invalid component name: "' + name + '". Component names ' + 'can only contain alphanumeric characaters and the hyphen.');
					name = null;
				}
			}
			var Sub = createClass(name || 'VueComponent');
			Sub.prototype = Object.create(Super.prototype);
			Sub.prototype.constructor = Sub;
			Sub.cid = cid++;
			Sub.options = mergeOptions(Super.options, extendOptions);
			Sub['super'] = Super;
			// allow further extension
			Sub.extend = Super.extend;
			// create asset registers, so extended classes
			// can have their private assets too.
			config._assetTypes.forEach(function(type) {
				Sub[type] = Super[type];
			});
			// enable recursive self-lookup
			if(name) {
				Sub.options.components[name] = Sub;
			}
			// cache constructor
			if(isFirstExtend) {
				extendOptions._Ctor = Sub;
			}
			return Sub;
		};

		/**
		 * A function that returns a sub-class constructor with the
		 * given name. This gives us much nicer output when
		 * logging instances in the console.
		 *
		 * @param {String} name
		 * @return {Function}
		 */

		function createClass(name) {
			/* eslint-disable no-new-func */
			return new Function('return function ' + classify(name) + ' (options) { this._init(options) }')();
			/* eslint-enable no-new-func */
		}

		/**
		 * Plugin system
		 *
		 * @param {Object} plugin
		 */

		Vue.use = function(plugin) {
			/* istanbul ignore if */
			if(plugin.installed) {
				return;
			}
			// additional parameters
			var args = toArray(arguments, 1);
			args.unshift(this);
			if(typeof plugin.install === 'function') {
				plugin.install.apply(plugin, args);
			} else {
				plugin.apply(null, args);
			}
			plugin.installed = true;
			return this;
		};

		/**
		 * Apply a global mixin by merging it into the default
		 * options.
		 */

		Vue.mixin = function(mixin) {
			Vue.options = mergeOptions(Vue.options, mixin);
		};

		/**
		 * Create asset registration methods with the following
		 * signature:
		 *
		 * @param {String} id
		 * @param {*} definition
		 */

		config._assetTypes.forEach(function(type) {
			Vue[type] = function(id, definition) {
				if(!definition) {
					return this.options[type + 's'][id];
				} else {
					/* istanbul ignore if */
					if('development' !== 'production') {
						if(type === 'component' && (commonTagRE.test(id) || reservedTagRE.test(id))) {
							warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + id);
						}
					}
					if(type === 'component' && isPlainObject(definition)) {
						definition.name = id;
						definition = Vue.extend(definition);
					}
					this.options[type + 's'][id] = definition;
					return definition;
				}
			};
		});

		// expose internal transition API
		extend(Vue.transition, transition);
	}

	installGlobalAPI(Vue);

	Vue.version = '1.0.24';

	// devtools global hook
	/* istanbul ignore next */
	setTimeout(function() {
		if(config.devtools) {
			if(devtools) {
				devtools.emit('init', Vue);
			} else if('development' !== 'production' && inBrowser && /Chrome\/\d+/.test(window.navigator.userAgent)) {
				console.log('Download the Vue Devtools for a better development experience:\n' + 'https://github.com/vuejs/vue-devtools');
			}
		}
	}, 0);

	return Vue;

}));